使用DevKit精度分析工具解决GraphicsMagick图像转码/缩放精度不一致应用实践
发表于 2025/09/10
0
作者 | 余盼
一、介绍
用户在鲲鹏上使用GraphicsMagick对png格式图片进行转码/缩放操作时,发现图片在avif转码缩放png时(转码时就已经有差异),以及缩放jpg时, 鲲鹏和x86的表现会出现不一致。现象如下:
-
avif转码png时就会出现大小不一致的情况, 缩放时不确定是因为转码后图片已经不一样导致。
-
jpg缩放时会出现大小不一致。
初步怀疑是浮点精度问题,随即使用DevKit精度分析工具进行了问题定位与解决。DevKit精度分析工具安装及使用请参见《鲲鹏DevKit 用户指南(命令行)》。
二、环境信息
芯片配置
处理器厂商 | 鲲鹏服务器 |
型号 | 920 7282C |
基频 | 2.9G |
turbo最高频率 | / |
turbo全核频率 | / |
测试频率 | 2.9G |
核数 | 80C160T |
内存通道数 | 8 |
内存频率 | 4800 |
整机配置
配置项 | Kunpeng 920 7282C |
CPU | 920 7282C * 2 |
总核数 | 160 * 2 |
内存 | 32GB * 16 |
硬盘 | 480GB SATA * 1 |
操作系统 | openEuler 22.03 SP4 |
软件配置
配置项 | Kunpeng 920 7282C |
操作系统 | openEuler 22.03 SP4 |
图片处理转码库 | GraphicsMagick-1.3.38 |
编译器 | GCC |
三、测试
本次测试共准备50张jpg原图,10张png原图,20张avif原图,20张静态gif(由avif原图转码得到)。
以下测试通过cpp调用库函数实现,包含libGraphicsMagic、libavif、libturbojpeg、libpng、libgif。
在鲲鹏和x86上进行测试,部分测试结果如下:
avif缩放
avif缩放步骤为:
-
调用libavif将avif转为rgb。
-
调用libGraphicsMagic通过rgb进行缩放。
-
调用libavif将rgb转回avif。
将20张图片全部缩放到1080x1080,所有图片缩放后的大小都不一致,且部分图片的差距非常大。
jpg转avif
jpg转步骤为:
-
调用libjpg将jpg转为rgb。
-
调用libavif将rgb转回avif。
将20张图片全部转为avif,所有图片转码后的大小都不一致,且部分图片的差距非常大。
png转avif
png转步骤为:
-
调用libpng将png转为rgb。
-
调用libavif将rgb转为avif。
将10张图片全部转为avif,所有图片转码后的大小都不一致,且部分图片的差距非常大。
gif转avif
gif转步骤为:
-
调用libgif将gif转为rgb。
-
调用libavif将rgb转为avif。
将20张图片全部转为avif,所有图片转码后的大小都不一致,且部分图片的差距非常大。
四、问题定位
经定位人员的初步测试,将精度问题的入口位置设为图片转换命令gm convert -resize使用的文件resize.c中的HorizontalFilter函数,进行插桩操作。
x86上执行插桩与日志生成
x86上执行对目标文件与函数magick/resize.c:HorizontalFilter进行插桩的命令。
/home/csp/DevKit-CLI-25.0.0-Linux-x86-64/devkit advisor precision -instrument -c "make clean;make -j" -p /home/csp/GraphicsMagick-1.3.38 -e magick/resize.c:HorizontalFilter -d 2 -L
插桩后查看工具运行日志,插桩成功。运行插桩后的二进制,生成x86上面的日志。
鲲鹏上执行插桩与日志生成
鲲鹏上对目标文件与函数magick/resize.c:HorizontalFilter进行插桩。
/home/csp/DevKit-CLI-25.0.0-Linux-Kunpeng/devkit advisor precision -instrument -c "make clean;make -j" -p /home/jd_iamge/GraphicsMagick-1.3.38_csp/ -e magick/resize.c:HorizontalFilter -d 2 -L
插桩后查看工具运行日志,插桩成功。运行插桩后的二进制,生成鲲鹏上面的日志。
日志对比
将x86和鲲鹏上面生成的日志,统一放到同一台机器对比。生成结果文件。查看差异结果文件,发现框出的图像RGB值的hash值存在差异,怀疑可能是图像读取部分存在精度差异。
同时查看插桩日志,发现插桩过程中遍历了多个函数。但是最终只对入口文件函数magick/resize.c:HorizontalFilter进行了插桩。观察更下层调用的文件发现不涉及相关的图像操作。判断问题发生点就在当前函数内。
对于对应的变量,查看前述的差异对比日志,可以通过行号分别在x86和arm的源文件中找到对应的位置。
分析发现这些变量的变化基本由浮点运算决定。根据经验,怀疑是相关编译选项造成的精度不一致问题,进一步查看运行日志。
编译选项修复建议
工具运行日志中包含了一些警告项,例如编译选项修复建议、工具运行过程中的编译错误等,掌握这些警告信息能更好的发现问题。
查看x86和鲲鹏上面的工具运行日志,发现鲲鹏上面使用GCC编译器且未指定-ffp-contract时,会默认开启该优化选项,而在AMD的机器上对应的-mfma选项是默认关闭的,可能是造成精度不一致的原因。推荐定位人员修改编译选项重新测试后,精度达成一致。