【问题标题】:Can I speed this up any more?我可以再加快速度吗?
【发布时间】:2018-06-06 14:20:48
【问题描述】:

我有兴趣加快子程序 Compoundret 的计算时间,它基本上是在某个持有期(比如一个月、三个月、六个月等)内复合每月回报序列。 我将从 R 调用这个子例程作为 dll。我在附加的代码 sn-p 中编写了一个 main 函数,以使一切都在 fortran 中运行。

subroutine compoundret(R_c, R, RF, horizons, Tn, N, M)
  implicit none

  ! Arguments declarations
  integer, intent(in)  :: horizons(M), Tn, N, M
  real*8,  intent(in)  :: RF(Tn), R(Tn, N, M)
  real*8,  intent(out)  :: R_c(Tn, N, M)

  ! Intermediary Variables
  integer :: t, j, k
  real*8  :: RF_Temp(Tn, N, M)

  R_c = 0.0
  do t = 1, Tn
     RF_Temp(t,:,:) = RF(t)
  end do

  !$acc data copyin(r(Tn,N,M), RF_Temp(Tn,N,M), horizons(M)), create(R_c(Tn, 
  N, M))
  !$acc parallel loop
  do k = 1, M
    do j = 1, N
      do t = 1, Tn - horizons(k) + 1
        R_c( t, j, k) = PRODUCT( 1 + R( t:t + horizons(k) - 1, j, k) + &
                        RF_Temp( t:t + horizons(k) - 1, j, k)) - &
                        PRODUCT(1+ RF_Temp( t:t + horizons(k) - 1, j, k))
      end do
    end do
  end do
  !$acc end parallel
  !$acc update host(R_c)
  !$acc end data

end subroutine compoundret

Program main
    implicit none
    real*8  :: df(1000,5000, 6)
    real*8  :: retdata(size(df,1),size(df,2),size(df,3)),RF(size(df,1))
    integer :: horizons(6), Tn, N, M

  Tn = size(df, 1)
  N  = size(df, 2)
  M  = size(df, 3)

    df = 0.001
    RF = 0.001
    horizons(:) = (/1,3,6,12,24,48/)

    call compoundret(retdata,df,RF,horizons, Tn, N, M)
print*, retdata(1, 1, 1:M)

结束程序 我的目标平台是计算 6.0 设备 (GTX 1060)。

【问题讨论】:

  • 这不是 CUDA 而是 OpenACC
  • @Chiel 这是一个 OpenACC 代码,但我不介意通过 Cuda Fortran 内核将循环内的所有内容完全卸载到 GPU。
  • 检查临时数组的分配需要多长时间以及内存传输到GPU需要多长时间。
  • @VladimirF 这在 Fortran 中是否允许?在 C/C++ 中,这种表示法意味着堆栈分配,并且很可能导致堆栈溢出,因为如果数组不大,OP 可能不想优化此代码。
  • 编译器可以按照它想要的任何方式进行分配。不暗示堆栈分配。在这个程序中它是 228 MB。

标签: fortran openacc acceleration


【解决方案1】:

我建议折叠两个外部循环,然后在“t”循环上添加“!$acc 循环向量”。

  !$acc parallel loop collapse(2)
  do k = 1, M
    do j = 1, N
  !$acc loop vector
      do t = 1, Tn - horizons(k) + 1
        R_c( t, j, k) = PRODUCT( 1 + R( t:t + horizons(k) - 1, j, k) + &
                        RF_Temp( t:t + horizons(k) - 1, j, k)) - &
                        PRODUCT(1+ RF_Temp( t:t + horizons(k) - 1, j, k))
      end do
    end do
  end do
  !$acc end parallel

现在,您只是在并行化外部循环,并且由于“M”非常小,因此您没有充分利用 GPU。

请注意,PGI 2017 编译器有一个错误,它会阻止您在 DLL 中使用 OpenACC(Linux 上的共享对象很好)。我们正在努力解决 18.1 编译器中的这个问题。您当前的选择是要么等到明年初发布 18.1,要么回到 16.10 编译器。如果您使用的是 PGI 社区版,则需要等待 4 月份的 18.4 编译器。

此外,将 OpenACC 放入共享库或动态库中需要使用“-ta=tesla:nordc”选项。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-21
    • 1970-01-01
    • 2011-01-17
    • 2019-06-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多