定位一个llvm19 升级带来的性能问题

Posted by 叉叉敌 on October 27, 2025

问题: 在bitsandbytes里面,从llvm12升级到llvm19之后,部分性能下降。 matmul和double_quant,部分case性能下降6%~13%。 matmul的最后一个下降,13%

问题

思路是: 先复现这个问题,可以H列QA测试的结果保持一致。性能确实有回退。 先用内部工具,分析是哪一个kernel的占比耗时比较高。

这个工具可以参考cuda profiler之类的工具,可以统计到每一个kernel执行的cycle值。

同一个名称的 mangled 名称是一样的,mangled是带了参数的,所以不怕有不同参数的kernel 函数了。

通过AI,直接生成一个python脚本,来分析这个json文件,大文件,记得用ijson,不是json。

bYBsF6_Z9m52d

得到的数据,然后按照cycle的降序排序。 这个方法内部同事把这个定义为找hot kernel。 OVj49M_WfgZQn 可以看到这个回退的结果,里面其中一个kernel占比llvm12和19都是87%左右,挺大的,在看具体icycle值对比,也是回退和实际一致。

问题找到了,可以下结论了。就是这个kernel 主要导致了性能回退的原因。

那就开始深入分析kernel了,通过c++filt,可以看到这个kernel具体的名称,参数是什么?

找到kernel name之后,在对应的测试集,或者是模型里面,找到对应的device函数名称。

通过rg,或者grep 。找到这个函数在哪里。

找到之后, https://github.com/bitsandbytes-foundation/bitsandbytes/blob/main/csrc/kernels.cu:1766

开源的工具,在1766行。

是一个模板,看他实例化的地方, https://github.com/bitsandbytes-foundation/bitsandbytes/blob/main/csrc/ops.cu: 446行的地方,有2个是实例化,但是参数对的上的之后一个。

这个就好办了。

先make的时候 verbose=1,打印出编译命令,然后修改这个cu文件,只保留这么一个实例化, 这样就搞了一个mini-case来复现问题。

然后对比汇编。 fzgScS_UegfHX

可以看到llvm12的bb块多了很多,llvm19少了很多。

可能的原因就是bb块多了之后,走到一个有endk的bb块,直接就跳出了。所以性能好。

那就分析这个bb块是怎么来的,llvm19的bb块是怎么被优化没的。

首先,通过-print-after-all, -filter-function-print, 找到只包含这个kernel的情况,获取到IR文件。

用AI写一个python脚本,分析下这个只包含这个函数的bb块,变化情况。

初步找到是inline一个pass导致的, 9aRmZ8_6CxjMy

这个就是不优化的,地方,说明是从其他子函数带过来的bb块。需要从子函数来分析。

统计下print-after-inline后的bb情况变化, 可以看到llvm19是很高的。

KMg0Ih_hDlUVj

方向对了。 那在看print-after-all, 就看这个bb块什么时候减少了。 UdNu21_E20wQ0

可以看到前面都是73个bb块,后面就变成了17个, 就是这个simpfyCFG pass导致的,通过查看passBuilder pipeline这个pass。 找到对应的代码,主要上下的pass需要对应上,然后直接注释这个代码。

先看看汇编有变化没?有了

然后注释代码,看看性能怎么样? 正常了。

那就开始添加一个编译选项,专门控制这个地方,提供给bitsandbytes来使用。

ok,梳理代码,提交,合并到dev,等待验证结果。