我有一个带有内部循环的程序,由于它执行的迭代次数需要非常快。为了分析此代码,我一直在使用valgrind / callgrind。我发现它是一个很棒的工具。不幸的是,我在优化方面的努力使我不得不使用诸如fma(intel)/ fma4(amd)之类的更新指令集,并且每当我使用这些callgrind时,它们就会爆炸,因为它不支持这些指令。

我知道一种解决方案是使简单地不使用这些内在函数,并使编译器发出不包含那些指令的代码,但是老实说,我认为没有意义,我想按原样分析代码,而不像valgrind可以处理。

这使我想到了我的问题。 是否有可以像valgrind / callgrind一样出色的开源或免费分析器? 我了解gprof,但据我所知,它实际上只是每隔一段时间就停止程序,并查看它在哪里,并计算它看到每件事的次数,这就像把callgrind给我的眼睛撕裂了一样。

最佳答案

我可能会坚持使用valgrind / callgrind:

在不同的处理器上尝试mavxmfma4编译标志也会引起我的问​​题:FMA4主要是AMD功能,尽管对其的支持已过滤到Intel芯片中,而AVX主要是Intel功能(将支持过滤到了AMD芯片中)但是,在受支持的AMD基准AVX上,其性能实际上比使用SSE1 / 2/3/4慢(FMA4填充SSE5 123)。

使用这两种优化可能不是最好的方法,并且可能会导致您遇到的问题,因为它们实际上彼此对立,主要针对特定​​品牌的处理器而设计。如果要针对支持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;
}

10-06 11:09