2016-03-25 1 views
3

J'ai besoin de faire un produit scalaire dans Fortran. Je peux faire avec la fonction intrinsèque dot_product de Fortran ou utiliser ddot de OpenBLAS. Le problème est le ddot est plus lent. Ceci est mon code:OpenBLAS plus lent que la fonction intrinsèque dot_product

Avec 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 

Avec 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 

Les deux codes sont compilés à l'aide:

gfortran file_name.f90 -lblas -o file_name.e 

Qu'est-ce que je fais mal? BLAS ne doit pas être plus rapide?

+0

très liée http://stackoverflow.com/questions/35926940/ fortran-lapack-haut-cpu-sys-usage-avec-dsyev-no-parallelization-normal/36035152 # 36035152 –

Répondre

4

Alors que BLAS, et en particulier les versions optimisées, sont généralement plus rapides pour les grandes baies, les fonctions intégrées sont plus rapides pour les petites tailles.

Ceci est particulièrement visible à partir du code source lié de ddot, où un travail supplémentaire est consacré à d'autres fonctionnalités (par exemple, des incréments différents). Pour les petites longueurs de réseau, le travail effectué ici l'emporte sur le gain de performance des optimisations.

Si vous agrandissez vos vecteurs, la version optimisée devrait être plus rapide.

Voici un exemple pour illustrer ceci:

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 

Les routines BLAS sont tout à fait un peu plus vite ici:

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

@FNB Note: cela dépend aussi de l'implémentation de la bibliothèque BLAS que vous utilisez, et de la manière dont elle a été compilée. Le MKL est extrêmement efficace sur les processeurs Intel, et si vous venez d'installer openBLAS depuis le référentiel de paquets de votre distribution, il ne sera probablement pas idéalement adapté à votre architecture. –