FFmpeg H.265解码WASM SIMD优化进展

作者:quink
来源:Fun With FFmpeg
链接:https://mp.weixin.qq.com/s/nQNaRkyq0MUsAbXOR5UWSw

去年作为proof of concept,我写了H.265解码IDCT的wasm simd128加速,32×32的IDCT变换大约是8倍速。最近又增加了帧间预测部分和SAO滤波,实测解码速度的对比如下:

视频文件关闭simd128
解码速度/FPS
编译器自动向量化解码速度/FPSsimd intrinsic
解码速度/FPS
相比关闭simd128的提升相比自动向量化的提升
A5689133138%49%
B58659462%45%
C315078152%56%
D699212987%40%
  • 4个视频文件分辨率均为1920×1080,码率不同,开启的编码工具不同,解码速度不同,获得的加速效果也不同
  • 测试机CPU是intel 10代i7,wasmtime单线程解码

编译器自动向量化的提升已经很可观了,但和手写的优化还有差距,4个视频相比自动向量化平均提升48%。继续优化提升50%不是问题,上限还不好预测。

WASM simd128是从常见CPU架构指令集里抽取出来的交集,相比ARM少了很多操作,相比x86不光操作少,寄存器还只有128bit,发挥空间小。WASM的simd指令还在扩充中,用更新的指令集也是后续的一个优化方向。

接下来聊聊性能优化的“常规套路”。

首先,是优化哪里的问题。

做优化要找到热点函数。有的热点函数可以通过算法复杂度推测出来,更简单直接的方式还是测出来。

一般的native程序,可以通过Linux perf命令、Intel的VTune工具等来定位热点函数。Chrome貌似提供了工具来分析WASM性能,但我实在不熟悉Web上的工具。对于WASM程序,我选择的方案还是Linux perf命令。示例命令如下:

perf record -e cache-misses,cycles,instructions \
    wasmtime --profile=perfmap --wasi threads --dir=/ \
    ./ffmpeg -i h265.mp4 -an -frames:v 2000 -f null -

结束之后,再通过

perf report |vim -

来查看perf结果。关于怎么perf和debug,wasmtime提供了详细的文档,见 https://docs.wasmtime.dev/examples-profiling-perf.html

其次,怎么做优化。

直接用SIMD指令翻译现有的程序,是刚开始学习汇编加速易范的错误。算法稍微复杂一些,直接翻译会引入一堆冗余的指令,最终优化效果可能还不如编译器自动向量化的结果。根据可用的指令集,去改写算法实现方式,尤其是数据的读写,才能达到更好的加速效果。

根据指令集来改写算法,从算法到手写汇编或 intrinsic阶段,要考虑CPU架构的影响,特别是手写汇编,可以控制指令排序。

实现完代码之后是测试。

测试包括一致性测试来验证优化程序的正确性,速度测试来验证加速效果。修改实现方式,测试加速效果,多次循环迭代。不管是一致性测试还是速度测试,都有单元测试和系统测试的方式。对于FFmpeg来说

单元测试一致性

wasm ./tests/checkasm/checkasm --test=hevc_sao
checkasm: using random seed 2036468145
SIMD128:
 - hevc_sao.sao_band [OK]
 - hevc_sao.sao_edge [OK]
checkasm: all 10 tests passed

单元测试速度

wasm ./tests/checkasm/checkasm --test=hevc_sao --bench=hevc_sao_edge*
benchmarking with native FFmpeg timers
nop: 125.0
checkasm: using random seed 1973792141
checkasm: bench runs 1024 (1 << 10)
SIMD128:
 - hevc_sao.sao_band [OK]
 - hevc_sao.sao_edge [OK]
checkasm: all 10 tests passed
hevc_sao_edge_8_8_c:                                   119.2 ( 1.00x)
hevc_sao_edge_8_8_simd128:                              14.3 ( 8.31x)
hevc_sao_edge_16_8_c:                                  472.3 ( 1.00x)
hevc_sao_edge_16_8_simd128:                             35.7 (13.24x)
hevc_sao_edge_32_8_c:                                 1856.2 ( 1.00x)
hevc_sao_edge_32_8_simd128:                            119.6 (15.52x)
hevc_sao_edge_48_8_c:                                 4133.2 ( 1.00x)
hevc_sao_edge_48_8_simd128:                            253.9 (16.28x)
hevc_sao_edge_64_8_c:                                 7300.8 ( 1.00x)
hevc_sao_edge_64_8_simd128:                            435.0 (16.78x)

系统测试解码一致性

make fate-hevc -j10

TEST    hevc-conformance-AMP_A_Samsung_6
TEST    hevc-conformance-AMP_B_Samsung_4
TEST    hevc-conformance-AMP_A_Samsung_4
TEST    hevc-conformance-AMVP_A_MTK_4
TEST    hevc-conformance-AMP_B_Samsung_6
……

系统测试解码速度

wasm ./ffmpeg -i 1080P.mp4 -an -frames:v 2000 -f null - -benchmark

frame= 2000 fps=181 q=-0.0 Lsize=N/A time=00:01:20.00 bitrate=N/A speed=7.26x
bench: utime=11.022s stime=0.000s rtime=11.022s
bench: maxrss=0KiB

这是Apple M1上的解码速度,比10代i7高一大截。

最后,重头开始。每个函数的优化要迭代几轮,整体的优化也是循环的:perf找到热点函数,优化热点函数,再次perf看新的热点函数,优化热点函数……

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论