1

私の目標は、MATLAB から離れて、ほとんどの作業を Fortran で行うことです。これらの取り組みの 1 つは、MATLAB の parfor ループによる並列化を Fortran openMP ディレクティブに置き換えています。これは常に高速ですが、何らかの理由で CPU 使用率 (taskmgr で測定) は parfor よりも openMP を使用した方が低くなります (特に小さな問題の場合)。私の仮説は、これは通信のオーバーヘッドによるものであり、CPU 使用率が (MATLAB のように) 100% に近ければ、小さな問題のコードははるかに高速になるというものです。私の質問は 2 つあります。

  1. 次のコードの効率を (openMP ディレクティブで) 改善する方法はありますか?
  2. そうでない場合、非効率の原因は何ですか?それを改善するために何を提案しますか?

試行された (失敗した) 解決策:

  1. 句 collapse(5) の追加 (5 つのネストされたループの場合)
  2. すべてを明示的に宣言する (つまり、default(shared) を使用しない)
  3. KMP_SET_BLOCKTIME(1000) は、次の omp parallel do 実行までスレッドを開いたままにします

CPU 使用率データ (Windows 7 64 ビット、デュアル クアッドコア Intel Xeon 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)、時間: 96 秒、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
4

1 に答える 1

0

崩壊句を追加することで、非効率性が解消されました。!$omp do collapse(5) そうしないと、Jermiah Willcock が指摘したように、外側のループだけが並列に実行されます。6コアのコンピューターでテストしていたと思いますが、たまたま外側のループに6つのポイントがあったため、その時点で効率の低下はありませんでした. これが問題になったのは、より多くのコアを備えたコンピューターに切り替えたときだけでした。知っておくと良いです!

MSB と Jeremiah さん、迅速で役立つ回答をありがとうございました。すべてが今より良いです!

于 2013-04-25T12:14:14.173 に答える