我有一个带有内循环的程序,由于它执行的迭代次数需要非常快。要分析这段代码,我一直在使用valgrind / callgrind。我发现它是一个很棒的工具。不幸的是,我在优化方面的努力使我使用了更新的指令集,如fma(intel)/ fma4(amd),每当我使用这些callgrind时都会爆炸,因为它不支持这些指令。
我理解一个解决方案就是简单地不使用那些内在函数,并让编译器发出不包含那些指令的代码,但老实说,我认为没有意义,我想要按原样分析代码,而不是valgrind可以处理它。
这让我想到了我的问题。 是否有任何开源或免费的分析器可以像valgrind / callgrind那样做得好?我知道gprof,但据我所知,它基本上只是间隔停止程序并看到它在哪里,并计算它看到每件东西的次数,这就像扯了一眼,与callgrind给我的相比。
答案 0 :(得分:3)
我可能会坚持使用valgrind / callgrind:
在不同的处理器上尝试编译标志mavx
和mfma4
也会给我带来问题:FMA4主要是AMD的功能,虽然它支持过滤到Intel芯片,而AVX主要是英特尔功能(支持被过滤到AMD芯片)但是在AMD基准测试中,当支持时,AVX实际上比使用SSE1 / 2/3/4更慢(FMA4填写SSE5 1,2 ,3)。
使用这两种优化方法可能不是最好的方法,可能会导致您遇到的行为,因为它们有效地相互对立,主要是针对特定品牌的处理器而设计的。如果要编译支持AVX的Intel CPU,并在编译支持FMA4的AMD处理器时使用FMA4,请尝试删除FMA4。
话虽如此,编译器不会允许乘法和加入FMA的组合,因为这会在FMA中将2舍入减少到1舍入,因此,您需要使用宽松的浮点模型(类似于 - 通过转换lutiply并添加到FMA,ffast-math *
)或IEEE浮点符合性失败。当你专门调用内在函数时不确定它是如何工作的,但是编译器可能不会根据标志来优化它们,因为它们是非常具体的指令。
我的英特尔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 :整数向量乘法累加指令,整数向量水平加法,整数向量比较,移位和旋转指令,字节置换和条件移动指令,浮点分数提取。 FMA4 :浮点向量乘法累加。 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;
}