fortran - OpenBLAS más lento que la función intrínseca dot_product
(1)
Necesito hacer un producto de puntos en Fortran. Puedo hacer con la función intrínseca dot_product
de Fortran o usar ddot
desde OpenBLAS. El problema es que el ddot
es más lento. Este es mi código:
Con 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
Con 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
Los dos códigos se compilan usando:
gfortran file_name.f90 -lblas -o file_name.e
¿Qué estoy haciendo mal? BLAS no tiene que ser más rápido?
Mientras que BLAS, y especialmente las versiones optimizadas, son generalmente más rápidas para las matrices más grandes, las funciones integradas son más rápidas para tamaños más pequeños.
Esto es especialmente visible desde el código fuente vinculado de ddot
, donde se gasta trabajo adicional en funcionalidades adicionales (por ejemplo, diferentes incrementos). Para longitudes de matriz pequeñas, el trabajo realizado aquí supera la ganancia de rendimiento de las optimizaciones.
Si aumenta sus vectores (mucho), la versión optimizada debería ser más rápida.
Aquí hay un ejemplo para ilustrar esto:
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
Las rutinas BLAS son bastante más rápidas aquí:
OMP_NUM_THREADS=1 ./a.out
dot_product: 0.145999998
BLAS, ddot: 0.100000001