为什么调用N次串行子例程比调用N次相同子例程的并行版本快

时间:2019-06-22 15:26:31

标签: fortran openmp subroutine

我有一个子程序“ serial”的串行版本和一个子程序“ paral”的并行版本。我正在使用openmp。当我调用串行时钟时,我测量的挂钟时间为0.475秒。当我称并行信号时,我测量的是墙上时钟时间0.09309秒。总加速= 5倍,出色的结果。但是当我尝试:

    do jjj=1,10
         call serial
    end do

当我执行0.475 * 10 = 4.75秒时,我测量的挂钟时间为1.398秒。当我尝试相同的循环,但使用“ call paral”时,我测量了1.08秒。循环版本的总加速= 1.398 / 1.08 = 1.3X。不良结果。当串行子例程被多次调用时,它的伸缩性会很好。当并行子例程被多次调用时,它会线性缩放(如预期的那样)。有关此的一些建议?我希望即使使用循环版本也可以保持5倍加速。我正在使用gfortran。谢谢

编辑: 这里我用来衡量性能的代码,请编译为: 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:我进行了一些测试,似乎仅一次调用就看到了加速,这是由于使用了一些智能缓存所致。如果您将串行时序与Paral时序进行切换,则可以(仅通过调用)检查使用缓存带来的好处。实际的加速是在多次调用子例程时测得的。

0 个答案:

没有答案