我有一些用numpy编写的代码,我正在考虑将它移植到Fortran以获得更好的性能。
我做过几次的一个操作就是将两个数组的元素乘积相加:
sum(A*B)
看起来融合的乘法 - 加法指令会对此有所帮助。我当前的处理器不支持这些说明,所以我还无法测试。但是,我可能会升级到支持FMA3(Intel Haswell处理器)的新处理器。
有没有人知道用“-march = native”(或ifort等价物)编译程序是否足以让编译器(gfortran或ifort)明智地使用SIMD指令来优化代码,或者你认为我必须要编译器或代码吗?
答案 0 :(得分:3)
如果在具有SIMD的计算机上使用-march=native
,编译器应该生成SIMD指令,尽管我总是使用-xHost
标志而不是ifort。
但我不太确定如何让他们“明智地”做到这一点。我的感觉是,在-O3
级别,ifort和gfortran在向量化方面往往都过于激进(也就是说,他们使用SIMD功能的次数比他们应该的要多)。我经常要关闭矢量化以获得最有效的代码。当然,这对你来说可能适用也可能不适用。
使用针对此任务优化的矢量库通常会更好。您可以在MKL中使用vdmul
或在GSL中使用gsl_vector_mul
来执行此操作。
使用-march=NEWARCH
将导致为体系结构NEWARCH调整代码,但无法在早期架构上运行。您可以使用-mtune=NEWARCH
标志,其中NEWARCH是新处理器的体系结构。这将生成针对新架构调整的代码,但仍可在旧架构上执行。由于您还没有新机器,-mtune
可能就是您目前所需要的。
使用ifort,您可以使用矢量化报告标志来显示程序的哪个部分已被矢量化。例如,ifort
标志-vec-report=1
将在编译期间为您提供此类信息。我相信gfortran会有一个等效的旗帜。
答案 1 :(得分:2)
sum(a*b)
提供比dot_product(a,b)
更好的矢量化的gfortran版本已经过时了。您显示的代码是使用串行AVX2 fma指令。
在dot_product
的实现中没有间接索引或其他并发症(单独一个简单的循环),fma可能比simd并行乘法和加法指令的组合慢,因为乘法可以在延迟关键路径。 gfortran对dot_product使用并行simd fma在更复杂的情况下可能非常有效。
您需要-O2 -ftree-vectorize -ffast-math -march=native or -O3 -ffast-math -march=native
(以及合适的矢量长度)来对其进行矢量化,并且gfortran可能无法在OpenMP并行区域内进行矢量化。
gfortran 4.9似乎放弃了选项-ftree-vectorizer-verbose。 -fdump-tree-vect将矢量化传递的详细信息写入.vect文件,为不同的主要gcc版本选择不同的名称。
答案 2 :(得分:1)
感谢朱小磊的提示,我现在知道gfortran会使用融合乘法加法来优化sum(A*B)
。例如,使用以下代码:
程序测试 隐含无
real,dimension(7):: a,b
a =(/ 2.0,3.0,5.0,7.0,11.0,13.0,17.0 /)
b =(/ 4.0,6.0,8.0,10.0,12.0,14.0,16.0 /)
打印*,总和(a * b)
endprogram
我可以使用f95 sum.f95 -o sum -O3 -march=core-avx2
进行编译,objdump -d sum | grep vfmadd
显示
40088b:c4 e2 71 99 44 24 30 vfmadd132ss 0x30(%rsp),%xmm1,%xmm0
400892:c4 e2 69 b9 44 24 34 vfmadd231ss 0x34(%rsp),%xmm2,%xmm0
400899:c4 e2 61 b9 44 24 38 vfmadd231ss 0x38(%rsp),%xmm3,%xmm0
4008a0:c4 e2 59 b9 44 24 3c vfmadd231ss 0x3c(%rsp),%xmm4,%xmm0
4008a7:c4 e2 51 b9 44 24 40 vfmadd231ss 0x40(%rsp),%xmm5,%xmm0
4008ae:c4 e2 49 b9 44 24 44 vfmadd231ss 0x44(%rsp),%xmm6,%xmm0
4008b5:c4 e2 41 b9 44 24 48 vfmadd231ss 0x48(%rsp),%xmm7,%xmm0
因此gfortran展开循环并输入7个融合的乘法 - 加法指令。如果我创建更大,随机,多维的数组,我仍然会看到vfmadd231ss弹出一次(因此它不会展开循环)。