【问题标题】:Peculiar difference in MKL matrix multiplication performance between Fortran/Python/MATLABFortran/Python/MATLAB 之间 MKL 矩阵乘法性能的特殊差异
【发布时间】:2015-09-15 13:31:04
【问题描述】:

我编写了一个简单的基准测试,比较了三种语言的矩阵乘法性能 - 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 以 2-3 倍的倍数击败两者。我想知道为什么。

这是我用于 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

请注意,如果您的系统时钟频率不是我的情况下的 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"

最后是 MATLAB sn-p:

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'])

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

Fortran: 38.08 ms
Python: 104.29 ms
MATLAB: 97.36 ms

CPU 使用在所有三种情况下都无法区分(在计算期间启用了 HT 的 i7-920D0 处理器上使用稳定的 47-49%)。此外,对于任意矩阵大小,相对性能大致相同,但对于非常小的矩阵(N

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

【问题讨论】:

  • 如评论:不要计时,只需计时乘法!
  • 为什么要查询system_clock() 费率,而不是用cpu_time() 衡量时间?使用其中一种,它们有不同的用途。
  • 其中一个原因可能是for 循环,尽管看起来很愚蠢。 python/matlab 中的循环通常比 C/Fortran 慢。正如@AnderBiguri 建议的那样,尝试仅对矩阵乘法进行计时,选择 100 个计时并用 3 种语言对其进行平均。

标签: performance matlab fortran linear-algebra intel-mkl


【解决方案1】:

这里有两个问题:

  1. 在 Python 中,您可以对随机初始化和计算进行计时,而在 Fortran 和 MATLAB 中则不需要
  2. 在 Fortran 中,您测量 CPU 时间,而在 Python 和 MATLAB 中测量经过的时间。由于您注意到 CPU 使用率约为 46%,这可能只是造成差异的原因。

只需修复这两个问题,然后重试...您可能会考虑为此使用 date_and_time() 而不是 cpu_time()

【讨论】:

  • 很抱歉,这两个建议没有显着差异。 Python 现在可以更可靠地匹配 MATLAB,但使用 date_and_time() 函数的 Fortran 时序与以前完全相同,总体差异仍然存在。
  • 或者system_clock(),我发现它比date_and_time()更容易用于计时。
  • @VladimirF 实际上,system_clock() 可能更易于使用。我自己倾向于尽可能使用omp_get_wtime()
  • 您是否尝试将 KMP_NUM_THREADS 设置为 1 只是为了查看各种语言是否会导致有关并行化的不同策略?
  • 在转而使用system_clock() 对结果进行计时并考虑并行化差异之后,只要使用合理大小的矩阵,我现在可以得到所有三种语言几乎相同的结果。我也转移到只计时乘法而不是循环,但这并没有显着影响结果。感谢所有有用的 cmets,我会接受建议的答案,因为它总体上是最全面的以及附加的 cmets。
猜你喜欢
  • 2014-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-02
相关资源
最近更新 更多