Fortran/Python/MATLAB中MKL矩阵乘法性能的独特差异

use*_*492 4 performance matlab fortran linear-algebra intel-mkl

我写了一个简单的基准比较三种语言的矩阵乘法性能 - Fortran(使用Intel Parallel Studio 2015,用ifort开关编译:/ O3/Qopt-prefetch = 2/Qopt-matmul/Qmkl:parallel,这取代了MatMul调用调用英特尔MKL库),Python(使用当前的Anaconda版本,包括Anaconda Accelerate,提供与英特尔MKL库链接的NumPy 1.9.2)和MATLAB R2015a(再次使用英特尔MKL库进行矩阵乘法) ).

看看所有三种实现如何利用相同的英特尔MKL库进行矩阵乘法,我希望结果几乎相同,特别是对于足够大的函数调用开销变得微不足道的矩阵.然而,情况远非如此,而MATLAB和Python显示出几乎相同的性能,Fortran比这两倍都要好.我想明白为什么.

这是我用于Fortran版本的代码:

program MatMulTest

implicit none

integer, parameter :: N = 1024
integer :: i, j, cr, cm
real*8 :: t0, t1, rate
real*8 :: A(N,N), B(N,N), C(N,N)    

call random_seed()
call random_number(A)
call random_number(B)

! First initialize the system_clock
CALL system_clock(count_rate=cr)
CALL system_clock(count_max=cm)
rate = real(cr)
WRITE(*,*) "system_clock rate: ", rate

call cpu_time(t0)
do i = 1, 100, 1
    C=MatMul(A,B)                
end do
call cpu_time(t1)

write(unit=*, fmt="(a24,f10.5,a2)") "Average time spent: ", (t1-t0), "ms"
write(unit=*, fmt="(a24,f10.3)") "First element of C: ", C(1,1)

end program MatMulTest
Run Code Online (Sandbox Code Playgroud)

请注意,如果您的系统时钟速率不是10000,则需要相应地修改时序计算以产生毫秒数.

Python代码:

import time
import numpy as np

def main(N):
    A = np.random.rand(N,N)
    B = np.random.rand(N,N)
    for i in range(100):
        C = np.dot(A,B)
    print C[0,0]

if __name__ == "__main__":
    N = 1024
    t0 = time.clock()
    main(N)
    t1 = time.clock()
    print "Time elapsed: " + str((t1-t0)*10) + " ms"
Run Code Online (Sandbox Code Playgroud)

最后,MATLAB片段:

N=1024;
A=rand(N,N); B=rand(N,N);
tic;
for i=1:100
     C=A*B;
end
t=toc;
disp(['Time elapsed: ', num2str(t*10), ' milliseconds'])
Run Code Online (Sandbox Code Playgroud)

在我的系统上,结果如下:

Fortran: 38.08 ms
Python: 104.29 ms
MATLAB: 97.36 ms
Run Code Online (Sandbox Code Playgroud)

在所有三种情况下,CPU使用都无法区分(在计算期间,在i7-920D0处理器上使用稳定的47-49%w/HT).此外,对于任意矩阵大小,相对性能保持大致相等,除了对于非常小的矩阵(N <80左右),在Fortran中手动禁用并行化是有用的.

这里的差异有没有确定的原因?难道我做错了什么?我希望至少对于较大的矩阵,Fortran在这种情况下没有任何有意义的优势.

Gil*_*les 6

你有两个问题:

  1. 在Python中,您可以计算随机初始化以及计算,而Fortran和MATLAB则没有
  2. 在Fortran中,您可以在Python和MATLAB中测量经过的时间来测量CPU时间.而且,由于您注意到CPU使用率约为46%,这可能只是解释了差异.

只需修复这两件事并重试......您可以考虑使用date_and_time()而不是cpu_time()为此目的.

  • 或者`system_clock()`,我发现它比`date_and_time()`更容易用于计时. (2认同)
  • @VladimirF确实,`system_clock()`可能更容易使用.我自己倾向于尽可能使用`omp_get_wtime()`. (2认同)
  • 在转移到使用`system_clock()`来计算结果以及解决并行化差异之后,只要使用合理大小的矩阵,我现在得到几乎相同的所有三种语言的结果.我也转移到只计时乘法而不是循环,但这并没有显着影响结果.感谢所有有用的评论,我会接受提议的答案,因为它总体上是最全面的,附有评论. (2认同)