我有一个带有内部循环的程序,由于它执行的迭代次数需要非常快。为了分析此代码,我一直在使用 valgrind/callgrind。我发现它是一个很棒的工具。不幸的是,我在优化方面的努力使我开始使用新的指令集,例如 fma (intel)/fma4 (amd),每当我使用这些 callgrind 时就会崩溃,因为它不支持这些指令。
我知道一种解决方案是简单地不使用这些内在函数,并让编译器发出不包含这些指令的代码,但老实说,我认为这样做没有任何意义,我想按原样分析代码, valgrind 无法处理它。
这引出了我的问题。 是否有任何开源或免费的分析器可以像 valgrind/callgrind 一样出色?我了解 gprof,但据我了解,它本质上只是偶尔停止程序并查看它在哪里,并计算它看到每个东西的次数,与 callgrind 给我的东西相比,这就像撕掉一只眼睛。
最佳答案
我可能会坚持使用 valgrind/callgrind:
在不同的处理器上尝试编译标志 mavx
和 mfma4
也会给我带来问题:FMA4 主要是 AMD 功能,尽管对它的支持正在过滤到 Intel 芯片中,而 AVX 主要是 Intel 功能(支持被过滤到 AMD 芯片中),但是在 AMD 上的基准测试中,当支持 AVX 时,实际上执行速度比使用 SSE1/2/3/4 慢(FMA4 填充 SSE5 1 、 2 、 3 )。
使用这两种优化可能不是最好的方法,并且很可能会导致您遇到的行为,因为它们实际上是相互对立的,主要是为特定品牌的处理器设计的。如果您正在为支持 AVX 的 Intel CPU 进行编译,请尝试删除 FMA4;如果您正在为支持 FMA4 的 AMD 处理器进行编译,请尝试使用 FMA4。
话虽如此,编译器不允许将乘法和加法组合到 FMA 中,因为这会将 FMA 中的 2 舍入减少为 1 舍入,因此,您需要使用宽松的浮点模型(类似于 - ffast-math *
) 或通过转换 lutiply 并添加到 FMA 来导致 IEEE 浮点合规性失败。不确定当您专门调用内在函数时它是如何工作的,但编译器可能不会根据标志优化它们,因为它们是非常具体的指令。
我的 Intel CPU 上的 FMA 标志 (mfma4
) 可靠地产生相同的结果,valgrind 抛出与您发布的类似的嘶嘶声,但它在 AMD CPU 机器上表现良好,(我想你的处理器是英特尔的?):
vex amd64->IR: unhandled instruction bytes: 0xC4 0x43 0x19 0x6B 0xE5 0xE0 0xF2 0x44
vex amd64->IR: REX=0 REX.W=0 REX.R=1 REX.X=0 REX.B=1
vex amd64->IR: VEX=1 VEX.L=0 VEX.nVVVV=0xC ESC=0F3A
vex amd64->IR: PFX.66=1 PFX.F2=0 PFX.F3=0
这是来自下面的测试代码。
FMA3 内在函数:(AVX2 - Intel Haswell)
_mm_fmadd_pd(), _mm256_fmadd_pd()
_mm_fmadd_ps(), _mm256_fmadd_ps()
除此之外还有很多很多......
FMA4 内在函数:(XOP - AMD Bulldozer)
_mm_macc_pd(), _mm256_macc_pd()
_mm_macc_ps(), _mm256_macc_ps()
除此之外还有很多很多......
注释
FMA 为计划成为 SSE5 一部分的功能提供支持,例如:
XOP:整数 vector 乘法累加指令、整数 vector 水平加法、整数 vector 比较、移位和旋转指令、字节排列和条件移动指令、浮点分数提取。 FMA4:浮点 vector 乘法累加。 F16C:半精度浮点转换。
测试代码
float vfmaddsd_func(float f1, float f2, float f3){
return f1*f2 + f3;
}
int main() {
float f1,f2,f3;
f1 = 1.1;
f2 = 2.2;
f3 = 3.3;
float f4 = vfmaddsd_func(f1,f2,f3);
printf("%f\n", f4);
return 0;
}
关于c++ - callgrind 有合理的替代品吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22801787/