使用 f2py 编译 Fortran 代码时如何使用 avx 标志?

How do I use the avx flag when compiling Fortran code using f2py?

在 Python 中做一些性能测试时,我比较了不同方法计算坐标数组之间欧氏距离的时间。我发现我的 Fortran 代码是用 F2PY to be roughly 4x slower than the C implementation used by SciPy 编译的。将该 C 代码与我的 Fortran 代码进行比较,我看不出会导致 4 倍差异的根本差异。这是我的代码(有一些注释解释了它的用途):

        subroutine distance(coor,dist,n)
        double precision coor(n,3),dist(n,n)
        integer n,i,j
        double precision xij,yij,zij

cf2py   intent(in):: coor,n
cf2py   intent(in,out):: dist
cf2py   intent(hide):: xij,yij,zij,

       do 200,i=1,n-1
           do 300,j=i+1,n
               xij=coor(i,1)-coor(j,1)
               yij=coor(i,2)-coor(j,2)
               zij=coor(i,3)-coor(j,3)

               dist(i,j)=dsqrt(xij*xij+yij*yij+zij*zij)

  300   continue
  200   continue

        end

c         1         2         3         4         5         6         7
c123456789012345678901234567890123456789012345678901234567890123456789012
c
c     to setup and incorporate into python (requires numpy):
c
c     # python setup_distance.py build
c     # cp build/lib*/distance.so ./
c
c     to call this from python add the following lines:
c
c     >>> import sys ; sys.path.append('./')
c     >>> from distance import distance
c
c     >>> dist = distance(coor, dist)

查看F2PY的编译命令运行,我发现没有avx编译标志。我尝试使用 extra_compile_args=['-mavx]` 在 Python 安装文件中添加它,但这对 F2PY 的编译命令 运行 没有任何改变:

compiling Fortran sources
Fortran f77 compiler: /usr/bin/gfortran -Wall -g -ffixed-form -fno-second-underscore -fPIC -O3 -funroll-loops
Fortran f90 compiler: /usr/bin/gfortran -Wall -g -fno-second-underscore -fPIC -O3 -funroll-loops
Fortran fix compiler: /usr/bin/gfortran -Wall -g -ffixed-form -fno-second-underscore -Wall -g -fno-second-underscore -fPIC -O3 -funroll-loops
compile options: '-I/home/user/anaconda/lib/python2.7/site-packages/numpy/core/include -Ibuild/src.linux-x86_64-2.7 -I/home/user/anaconda/lib/python2.7/site-packages/numpy/core/include -I/home/user/anaconda/include/python2.7 -c'
gfortran:f77: ./distance.f
creating build/lib.linux-x86_64-2.7
/usr/bin/gfortran -Wall -g -Wall -g -shared build/temp.linux-x86_64-2.7/build/src.linux-x86_64-2.7/distancemodule.o build/temp.linux-x86_64-2.7/build/src.linux-x86_64-2.7/fortranobject.o build/temp.linux-x86_64-2.7/distance.o -L/home/user/anaconda/lib -lpython2.7 -lgfortran -o build/lib.linux-x86_64-2.7/distance.so

在评论中,Warren Weckesser 解释说 Fortran 数组是相对于 C 数组转置存储的。但是,没有提到一个重要的含义。要以正确的顺序遍历数组,您必须切换循环的顺序。在 C 中,第一个索引是外循环,在 Fortran 中,第一个索引应该是内循环。您正在索引为 dist(i,j),因此您的循环顺序错误。

但是因为您的 j 循环依赖于 i 循环值,您可能必须切换数组中索引的角色(转置)。

一些编译器能够通过足够高的优化级别为您纠正一些简单的循环顺序。

顺便说一句,众所周知,-funroll-loops 通常过于激进,实际上是有害的。通常应该设置一些限制。

回答如何将 avx 标志添加到编译器选项中。
在您的情况下,正在选择 f77 编译器 gfortran:f77: ./distance.f < 这是关键行。
您可以尝试指定 --f77flags=-mavx