我有一个带有内部循环的程序,由于它执行的迭代次数需要非常快。为了分析此代码,我一直在使用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机器上表现良好,(我认为您的处理器是Intel?) :
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-英特尔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;
}