У меня есть последовательная версия подпрограммы "serial" и параллельная версия e той же подпрограммы "paral". Я использую openmp. Когда я вызываю серийный номер, я измеряю 0,475 секунды времени настенных часов. Когда я вызываю параллельную, я измеряю 0,09309 секунд времени настенных часов. Общее ускорение = 5Х, отличный результат. Но когда я пытаюсь:
do jjj=1,10
call serial
end do
Я измерил 1,398 секунды времени настенных часов, когда я ожидал 0,475 * 10 = 4,75 секунды. Когда я пробую ту же петлю, но с «call paral», я измеряю 1,08 секунды. Общее ускорение версий цикла = 1.398 / 1.08 = 1.3 X. Плохие результаты. Когда последовательная подпрограмма вызывается много раз, она слишком хорошо масштабируется. Когда параллельная подпрограмма вызывается много раз, она масштабируется линейно (как и ожидалось). Некоторые предложения по этому поводу? Я хочу сохранить 5-кратное ускорение даже с версией петли. Я использую гфортран. Спасибо
EDIT:
и вот код, который я использую для измерения производительности, пожалуйста, скомпилируйте с:
gfortran -fopenmp -fdefault-real-8 -fdefault-integer-8 -fdefault-double-8 -mcmodel = большой код.f
PARAMETER(KMM1=80, JM=500 , IMM1=80 )
COMMON/VEC/ AQX(IMM1,JM,KMM1),AQR(IMM1,JM,KMM1),
& ROVX(IMM1,JM,KMM1),RR(IMM1,JM,KMM1),
& FX(IMM1,JM,KMM1),XX(IMM1,JM,KMM1),
& SE(IMM1,JM,KMM1)
COMMON/VRB/ KMMM,JMMM,IMMM
include 'omp_lib.h'
DOUBLE PRECISION SEC,SEC1,SEC11,SEC22
KMMM=80
JMMM=500
IMMM=80
CALL OMP_SET_NUM_THREADS(4)
SEC1 = omp_get_wtime()
do JJJJ=1,10
CALL SERIAL
END DO
SEC = omp_get_wtime() - SEC1
WRITE(6,*) '#CPU SERIAL=', SEC, 'SECONDS.'
SEC11 = omp_get_wtime()
DO JJJJ=1,10
CALL PARAL
END DO
SEC22 = omp_get_wtime() - SEC11
WRITE(6,*) '#CPU PARALLEL=', SEC22, 'SECONDS.'
WRITE(6,*) 'SPEEDUP = ', SEC/SEC22
STOP
END
SUBROUTINE SERIAL
PARAMETER(KMM1=80, JM=500 , IMM1=80 )
COMMON/VEC/ AQX(IMM1,JM,KMM1),AQR(IMM1,JM,KMM1),
& RX(IMM1,JM,KMM1),RR(IMM1,JM,KMM1),
& FX(IMM1,JM,KMM1),XX(IMM1,JM,KMM1),
& SE(IMM1,JM,KMM1)
COMMON/VRB/ KMMM,JMMM,IMMM
DO K=1,KMMM
DO J=1,JMMM
DO I=1,IMMM
AX = RX(I,J,K)+RX(I,J,K+1)+RX(I+1,J,K)+RX(I+1,J,K+1)
AR = RR(I,J,K)+RR(I,J,K+1)+RR(I+1,J,K)+RR(I+1,J,K+1)
FX(I,J,K) = 0.25*(AX*AQX(I,J,K) + AR*AQR(I,J,K))
SE(I,J,K ) = 0.0
XX(I,J,K) = FX(I,J,K)
END DO
END DO
END DO
RETURN
END
SUBROUTINE PARAL
include 'omp_lib.h'
PARAMETER(KMM1=80, JM=500, IMM1=80 )
COMMON/VEC/ AQX(IMM1,JM,KMM1),AQR(IMM1,JM,KMM1),
& RX(IMM1,JM,KMM1),RR(IMM1,JM,KMM1),
& FX(IMM1,JM,KMM1),XX(IMM1,JM,KMM1),
& SE(IMM1,JM,KMM1)
COMMON/VRB/ KMMM,JMMM,IMMM
!$OMP PARALLEL DO DEFAULT(NONE) PRIVATE(AX,AR)
!$OMP+ SHARED(RX,RR,AQX,AQR,SE,FX,XX,JMMM,IMMM,KMMM)
DO K=1,KMMM
DO J=1,JMMM
DO I=1,IMMM
AX = RX(I,J,K)+RX(I,J,K+1)+RX(I+1,J,K)+RX(I+1,J,K+1)
AR = RR(I,J,K)+RR(I,J,K+1)+RR(I+1,J,K)+RR(I+1,J,K+1)
FX(I,J,K) = 0.25*(AX*AQX(I,J,K) + AR*AQR(I,J,K))
SE(I,J,K ) = 0.0
XX(I,J,K) = FX(I,J,K)
END DO
END DO
END DO
!$OMP END PARALLEL DO
RETURN
END
EDIT2: я провел несколько тестов, и похоже, что ускорение, наблюдаемое только при одном вызове, было вызвано использованием интеллектуального кэша. Если вы переключаете последовательную синхронизацию с параллельной синхронизацией, вы можете проверить (только с вызовом), что выгода от использования кэша. Реальное ускорение измеряется при многократном вызове подпрограмм.