2016-03-25 13 views
3

Ich brauche ein Skalarprodukt in Fortran. Ich kann mit der intrinsischen Funktion dot_product von Fortran tun oder ddot von OpenBLAS verwenden. Das Problem ist, dass die ddot langsamer ist. Dies ist mein Code:OpenBLAS langsamer als intrinsische Funktion dot_product

Mit BLAS:

program VectorBLAS 
! time VectorBlas.e = 0.30s 
implicit none 
double precision, dimension(3) :: b 
double precision    :: result 
double precision, external  :: ddot 
integer, parameter    :: LargeInt_K = selected_int_kind (18) 
integer (kind=LargeInt_K)  :: I 

DO I = 1, 10000000 
    b(:) = 3 
    result = ddot(3, b, 1, b, 1) 
END DO 
end program VectorBLAS 

Mit dot_product

program VectorModule 
! time VectorModule.e = 0.19s 
implicit none 
double precision, dimension (3) :: b 
double precision     :: result 
integer, parameter    :: LargeInt_K = selected_int_kind (18) 
integer (kind=LargeInt_K)  :: I 

DO I = 1, 10000000 
    b(:) = 3 
    result = dot_product(b, b) 
END DO 
end program VectorModule 

Die beiden Codes verwenden zusammengestellt:

gfortran file_name.f90 -lblas -o file_name.e 

Was mache ich falsch? BLAS muss nicht schneller sein?

+0

sehr viel im Zusammenhang http://stackoverflow.com/questions/35926940/ fortran-lapack-high-CPU-sys-Nutzung-mit-dsyev-keine-Parallelisierung-normal/36035152 # 36035152 –

Antwort

4

Während BLAS und insbesondere die optimierten Versionen für größere Arrays im Allgemeinen schneller sind, sind die integrierten Funktionen für kleinere Größen schneller.

Dies ist besonders sichtbar aus dem verknüpften Quellcode von ddot, wo zusätzliche Arbeit für weitere Funktionalität (z. B. unterschiedliche Inkremente) ausgegeben wird. Bei kleinen Array-Längen überwiegt die hier durchgeführte Arbeit den Leistungsgewinn der Optimierungen.

Wenn Sie Ihre Vektoren (viel) größer machen, sollte die optimierte Version schneller sein.

Hier ist ein Beispiel zur Illustration:

program test 
    use, intrinsic :: ISO_Fortran_env, only: REAL64 
    implicit none 
    integer     :: t1, t2, rate, ttot1, ttot2, i 
    real(REAL64), allocatable :: a(:),b(:),c(:) 
    real(REAL64), external :: ddot 

    allocate(a(100000), b(100000), c(100000)) 
    call system_clock(count_rate=rate) 

    ttot1 = 0 ; ttot2 = 0 
    do i=1,1000 
    call random_number(a) 
    call random_number(b) 

    call system_clock(t1) 
    c = dot_product(a,b) 
    call system_clock(t2) 
    ttot1 = ttot1 + t2 - t1 

    call system_clock(t1) 
    c = ddot(100000,a,1,b,1) 
    call system_clock(t2) 
    ttot2 = ttot2 + t2 - t1 
    enddo 
    print *,'dot_product: ', real(ttot1)/real(rate) 
    print *,'BLAS, ddot: ', real(ttot2)/real(rate) 
end program 

Die BLAS-Routinen sind ziemlich viel schneller hier:

OMP_NUM_THREADS=1 ./a.out 
dot_product: 0.145999998  
BLAS, ddot: 0.100000001 
+0

@FNB Hinweis: Es hängt auch davon ab, welche Implementierung der BLAS-Bibliothek, die Sie verwenden, und wie es kompiliert wurde. Das MKL ist extrem effizient auf Intel-CPUs, und wenn Sie openBLAS nur aus dem Paket-Repository Ihrer Distribution installiert haben, wird es wahrscheinlich nicht optimal auf Ihre Architektur abgestimmt sein. –