如果我在Mac上使用gfortran (Homebrew GCC 8.2.0)
编译下面的简单程序而不进行优化(-O0
(,则对matmul
的调用将在约90毫秒内持续执行。如果我使用任何优化(标志-O1
、-O2
或-O3
(,执行时间将增加到~250毫秒。我已经尝试为inVect
和matrix
使用各种不同的大小,但在所有情况下,-O0
选项都比其他三个优化标志好,至少是的2.5倍。如果我使用只有几百个元素的较小矩阵,但循环多次调用matmul,则性能会更差,接近10倍。
有什么办法可以避免这种行为吗?我需要在代码的某些部分使用优化,但同时,我也希望尽可能高效地执行矩阵乘法。
我使用命令gfortran -ON sandbox.f90
编译包含以下代码的文件sandbox.f90
,其中N
是优化级别0-3(不使用其他编译器标志(。仅打印outVect
的第一个值是为了防止gfortran
优化过于巧妙并完全跳过对matmul
的调用。
我是Fortran新手,所以如果我在这里遗漏了一些明显的东西,我会提前道歉。
program main
implicit none
real :: inVect(20000), matrix(20000,10000), outVect(10000)
real :: start, finish
call random_number(inVect)
call random_number(matrix)
call cpu_time(start)
outVect = matmul(inVect, matrix)
call cpu_time(finish)
print '("Time = ",f10.7," seconds. – First Value = ",f10.4)',finish-start,outVect(1)
end program main
首先,考虑一下我可能错了。我只是第一次看到这个问题,我和你一样感到惊讶。
我刚刚研究了这个问题,我理解如下。优化-O0
、O3
、Ofast
和。。。是为大多数一般(常见(情况编写的。然而,在某些情况下(当-O3
的效率低于-O*<-O3
时(,优化会导致缺点。这是因为这些优化会隐式调用标志,从而降低特定任务的执行时间。对于您的情况,-O3
强制所有matmul()
函数都将内联。这样的事情通常是好的,但对于大数组或该函数的多次调用来说不是必须的。不知怎的,内联matmul()
的成本比内联函数获得的增益更重要(至少我是这样认为的(。
为了避免这种行为,我建议使用标志-O3 -finline-matmul-limit=0
来取消matmul
函数的内联。使用标志CCD_ 26导致不比针对CCD_ 27获得的执行时间差的执行时间。
只有当涉及的数组小于n
时,才能使用-finline-matmul-limit=n
内联matmul
函数。为了简单起见,我使用n=0
。
我希望这对你有帮助。