作者: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 | 编译器自动向量化解码速度/FPS | simd intrinsic 解码速度/FPS | 相比关闭simd128的提升 | 相比自动向量化的提升 |
---|---|---|---|---|---|
A | 56 | 89 | 133 | 138% | 49% |
B | 58 | 65 | 94 | 62% | 45% |
C | 31 | 50 | 78 | 152% | 56% |
D | 69 | 92 | 129 | 87% | 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 举报,一经查实,本站将立刻删除。