Как решить проблему пропускания памяти с помощью openmp fortrann77 - PullRequest
0 голосов
/ 06 июня 2019

Я пытаюсь распараллелить цикл do, который содержит много чтений из памяти.Код написан на фортране 77.

У меня вообще нет ускорения.Это распараллеленный код.Это дает правильные результаты.В коде A, B, C, D это массивы, определенные в общих разделах, таких как COMMON / ARR / A (IM, JM, KM), ETC ... и цикл является частью подпрограммы, которая вызывается много раз.

!$OMP PARALLEL DO DEFAULT(NONE) PRIVATE(AVGRVX,AVGRVR) 
!$OMP+ SHARED(A,B,AQX,AQR,SOURCEP,C,D,JMMM,IMMM)

 DO K=1,KMMM
 DO J=1,JMMM  
 DO I=1,IMMM
      AVGRVX = A(I,J,K)+A(I,J,K+1)+A(I+1,J,K)+A(I+1,J,K+1)
      AVGRVR = B(I,J,K)+B(I,J,K+1)+B(I+1,J,K)+B(I+1,J,K+1)
      C(I,J,K)   = 0.25*(AVGRVX*AQX(I,J,K) + AVGRVR*AQR(I,J,K))
      SOURCEP(I,J,K ) = 0.0
      D(I,J,K)   = C(I,J,K)
 END DO
 END DO
 END DO
!$OMP END PARALLEL DO

Фактическое ускорение составляет 0,98 X. Параллельная версия работает медленнее, чем последовательная.Я думаю, это потому, что каждый поток не выполняет много вычислений, а просто постоянно обращается к памяти.Это не из-за размеров JMMM, KMMM и т. Д. Если они становятся больше, тогда код становится еще медленнее.Я ищу предложения о том, как улучшить код.Может ли перевод кода, например, в fortran90 / 95 и использование выделяемых вместо общих массивов, принести некоторые преимущества?Спасибо

РЕДАКТИРОВАТЬ: Вот код, который я использую для проверки цикла, с gfortran, пожалуйста, скомпилируйте с gfortran -fopenmp -fdefault-real-8 -fdefault-integer-8 -fdefault-double-8 -mcmodel= большой -O3 этот код.f:

  PARAMETER(KMM1=70, JM=2500 , IMM1=70  )
  COMMON/VEC/ AQX(IMM1,JM,KMM1),AQR(IMM1,JM,KMM1), 
 &           A(IMM1,JM,KMM1),B(IMM1,JM,KMM1),           
 &           C(IMM1,JM,KMM1),D(IMM1,JM,KMM1),
 &           SOURCE(IMM1,JM,KMM1)


  COMMON/PARVEC/ CP(IMM1,JM,KMM1),SOURCEP(IMM1,JM,KMM1),
 &               DP(IMM1,JM,KMM1)
  COMMON/VRB/ KMMM,JMMM,IMMM
  include 'omp_lib.h'
  DOUBLE PRECISION SEC,SEC1


  KMMM=60
  JMMM=150
  IMMM=60

  CALL OMP_SET_NUM_THREADS(4)
  CALL RANDOM_SEED()

  DO K=1,KMM1
  DO J=1,JM
  DO I=1,IMM1

      CALL RANDOM_NUMBER(A(I,J,K))
      CALL RANDOM_NUMBER(B(I,J,K))
      CALL RANDOM_NUMBER(AQX(I,J,K))
      CALL RANDOM_NUMBER(AQR(I,J,K))
      CALL RANDOM_NUMBER(SOURCE(I,J,K))



  END DO
  END DO
  END DO

  SEC1 = omp_get_wtime()
  CALL SERIAL
  SEC = omp_get_wtime() - SEC1
  WRITE(6,*) '#CPU SERIAL=', SEC, 'SECONDS.'

  SEC1 = omp_get_wtime()

  CALL PARAL


  SEC = omp_get_wtime() - SEC1
  WRITE(6,*) '#CPU PARALLEL=', SEC, 'SECONDS.'





  DO K=1,KMM1
  DO J=1,JM
  DO I=1,IMM1

  IF(CP(I,J,K).NE.C(I,J,K)) THEN
      WRITE(6,*) 'ERROR'
  END IF
  IF(DP(I,J,K).NE.D(I,J,K)) THEN
      WRITE(6,*) 'ERROR'
  END IF

  END DO
  END DO
  END DO



  STOP
  END






  SUBROUTINE SERIAL
  PARAMETER(KMM1=70, JM=2500 , IMM1=70  )
  COMMON/VEC/ AQX(IMM1,JM,KMM1),AQR(IMM1,JM,KMM1), 
 &           A(IMM1,JM,KMM1),B(IMM1,JM,KMM1),           
 &           C(IMM1,JM,KMM1),D(IMM1,JM,KMM1),
 &           SOURCE(IMM1,JM,KMM1)


  COMMON/PARVEC/ CP(IMM1,JM,KMM1),SOURCEP(IMM1,JM,KMM1),
 &               DP(IMM1,JM,KMM1)
  COMMON/VRB/ KMMM,JMMM,IMMM



  DO K=1,KMMM
  DO J=1,JMMM  
  DO I=1,IMMM
      AVGRVX = A(I,J,K)+A(I,J,K+1)+A(I+1,J,K)+A(I+1,J,K+1)
      AVGRVR = B(I,J,K)+B(I,J,K+1)+B(I+1,J,K)+B(I+1,J,K+1)
      C(I,J,K)   = 0.25*(AVGRVX*AQX(I,J,K) + AVGRVR*AQR(I,J,K))
      SOURCE(I,J,K ) = 0.0
      D(I,J,K)   = C(I,J,K)
  END DO
  END DO
  END DO






  RETURN
  END


  SUBROUTINE PARAL



  PARAMETER(KMM1=70, JM=2500 , IMM1=70  )
  COMMON/VEC/ AQX(IMM1,JM,KMM1),AQR(IMM1,JM,KMM1), 
 &           A(IMM1,JM,KMM1),B(IMM1,JM,KMM1),           
 &           C(IMM1,JM,KMM1),D(IMM1,JM,KMM1),
 &           SOURCE(IMM1,JM,KMM1)


  COMMON/PARVEC/ CP(IMM1,JM,KMM1),SOURCEP(IMM1,JM,KMM1),
 &               DP(IMM1,JM,KMM1)
  COMMON/VRB/ KMMM,JMMM,IMMM





!$OMP PARALLEL DO DEFAULT(NONE) PRIVATE(AVGRVX,AVGRVR) 
!$OMP+ SHARED(A,B,AQX,AQR,SOURCEP,CP,DP,JMMM,IMMM)
  DO K=1,KMMM
  DO J=1,JMMM  
  DO I=1,IMMM
      AVGRVX = A(I,J,K)+A(I,J,K+1)+A(I+1,J,K)+A(I+1,J,K+1)
      AVGRVR = B(I,J,K)+B(I,J,K+1)+B(I+1,J,K)+B(I+1,J,K+1)
      CP(I,J,K)   = 0.25*(AVGRVX*AQX(I,J,K) + AVGRVR*AQR(I,J,K))
      SOURCEP(I,J,K ) = 0.0
      DP(I,J,K)   = CP(I,J,K)
  END DO
  END DO
  END DO
!$OMP END PARALLEL DO



  RETURN
  END
...