【问题标题】:fortran openmp nested loop communication overheadfortran openmp 嵌套循环通信开销
【发布时间】:2013-04-18 07:10:16
【问题描述】:

我的目标是离开 MATLAB,转而使用 Fortran 完成我的大部分工作。其中一项努力是通过 MATLAB 的 parfor 循环将并行化替换为 Fortran openMP 指令。这总是更快,但由于某种原因,使用 openMP 的 CPU 利用率(由 taskmgr 测量)低于 parfor(特别是对于较小的问题)。我的假设是,这是由于通信开销造成的,如果 CPU 利用率接近 100%(如 MATLAB),那么对于小问题,代码会快得多。我的问题有两个:

  1. 有没有办法提高以下代码的效率(使用 openMP 指令)?
  2. 如果不是,效率低下的根源是什么?您建议采取什么补救措施?

尝试(不成功)的解决方案:

  1. 添加子句 collapse(5)(用于 5 个嵌套循环)
  2. 明确声明所有内容(即不使用默认(共享))
  3. KMP_SET_BLOCKTIME(1000) 保持线程打开直到下一次 omp 并行执行

CPU 利用率数据(Windows 7 64 位,双四核英特尔至强 3Ghz):

  • 小问题(*_pts = 5):
    Fortran (openMP),时间:40 秒,CPU 利用率:60%
    MATLAB (parfor),时间:45 秒,CPU 利用率:90%
    -> MATLAB 耗时 1.125 倍

  • 中等问题(*_pts = 6):
    Fortran (openMP),时间:78 秒,CPU 利用率:75%
    MATLAB (parfor),时间:96s,CPU 利用率:90%
    -> MATLAB 耗时 1.231 倍

  • 大问题(*_pts = 7):
    Fortran (openMP),时间:150 秒,CPU 利用率:100%
    MATLAB (parfor),时间:205 秒,CPU 利用率:100%
    -> MATLAB 耗时 1.367 倍

例子:

    do while (converged == -1)
    istart = omp_get_wtime()               ! Iteration timer start
    !$omp parallel do default(shared) private(start,state,argzero)
    do i5 = 1,Oepsr_pts
     do i4 = 1,Ozeta_pts
      do i3 = 1,Oz_pts
       do i2 = 1,Or_pts
        do i1 = 1,Opd_pts
         start(1,1) = pfn(i1,i2,i3,i4,i5)
         start(2,1) = pfx1(i1,i2,i3,i4,i5)
         start(3,1) = pfx2(i1,i2,i3,i4,i5)
         state = [Gpd_grid(i1),Gr_grid(i2),Gz_grid(i3),Gzeta_grid(i4),Gepsr_grid(i5)];
         ! Find optimal policy functions on each node
         argzero = 0.d0
         call csolve(start,nstate,npf,nshock,Opd_pts,Or_pts,Oz_pts,Ozeta_pts,Oepsr_pts,Omono_pts,state, &
                        Smu,Schi,Sr,Sy,Pomega,Ptheta,Psigma,Peta,Pzbar, &
                        Prhor,Ppi,Pphipi,Pphiy,Prhoz,Pzetabar,Prhozeta,Pbeta, &
                        Gpd_grid,Gr_grid,Gz_grid,Gzeta_grid,Gepsr_grid,Gmono_nodes,Gmono_weight, &
                        pfn,pfx1,pfx2,argzero)
         ! Store updated policy functions
         pfn_up(i1,i2,i3,i4,i5) = argzero(1,1)
         pfx1_up(i1,i2,i3,i4,i5) = argzero(2,1)
         pfx2_up(i1,i2,i3,i4,i5) = argzero(3,1)
        end do
       end do
      end do
     end do
    end do
    !$omp end parallel do

    ! Policy function distances    
    dist_n = abs(pfn_up - pfn);  
    dist_x1 = abs(pfx1_up - pfx1);
    dist_x2 = abs(pfx2_up - pfx2);

    ! Maximum distance
    dist_max(it) = max(maxval(dist_n),maxval(dist_x1),maxval(dist_x2));

    ! Update policy functions
    pfn = pfn_up;
    pfx1 = pfx1_up;
    pfx2 = pfx2_up;

    ! Check convergence criterion
    if ((it > 11) .AND. all(dist_max(it-10:it) < Ptol)) then 
        converged = 1;
    else if (dist_max(it) > 10 .OR. it > 2500) then
        converged = 0;
    end if

    ! Iteration Information
    iend = omp_get_wtime()
    if (mod(it,3) == 1 .OR. converged == 1 .OR. converged == 0) then
        call itinfo(tstart,istart,iend,it,dist_max(it));
    else
        it = it + 1
    end if
end do

【问题讨论】:

  • 似乎在所有问题规模上,Fortran 实现都比 Matlab 版本好,并且随着问题的增大而变得更好。如果其中任何一个都不是真的,我会更担心。为什么要花很多精力在 40 秒内运行的东西上,除非你必须运行很多次?
  • 代码中的一个问题是it 似乎仅在与 1 mod 3 不一致时才会增加;你确定你想要else 子句中的增量吗?另外,这段代码在没有 OpenMP 的情况下可以完全使用一个 CPU 吗?
  • 如果不折叠循环,您的代码将无法获得比Oepsr_pts 更高的并行度;这足以解释有限的 CPU 利用率吗?我还认为i1...i4 应该标记为private,这样它们就可以为i5 循环的每次迭代单独迭代。
  • 1) 我计划针对问题的不同参数化运行它很多次(40,000 次),这就是为什么我想运行这个小问题。 2)它在调用 itinfo 时递增(未显示) 3)我会尝试再次折叠一次以验证,但是当我过去尝试过它时它不起作用。我还将 i1...i4 指定为私有,但无济于事。
  • 好吧,看来崩溃确实修复了它。我不确定为什么我认为它不起作用。我当时可能一直在使用具有不同内核数的不同计算机。

标签: fortran openmp


【解决方案1】:

添加折叠子句消除了低效率。 !$omp 崩溃(5) 否则,正如 Jermiah Willcock 指出的那样,只有外部循环会并行运行。我相信我是在一台6核的电脑上测试的,外环恰好有6个点,所以当时没有效率损失。只有当我切换到具有更多内核的计算机时,这才成为一个问题。很高兴知道!

谢谢 M.S.B.和耶利米,感谢您的快速和有益的回应。现在一切都好起来了!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-27
    • 1970-01-01
    • 2012-11-14
    • 2012-11-01
    • 1970-01-01
    相关资源
    最近更新 更多