パスワードを忘れた? アカウント作成
819712 journal
プログラミング

t-nissieの日記: 【電脳】どっちが速いのか 7

日記 by t-nissie

こういうのって、どっちが速いのかしらん。
Nxの大きさとキャッシュの大きさに関係するのかしらん。
プログラム全体からしたらゴミみたいなところだから影響は小さいのだけど。
equivalence文を使えばもっとクールに書けるかな。

before:

subroutine dfftw_plan_dft_c2r_3d(plan, Nx, Ny, Nz, c, r, flags)
  implicit none
  integer*8, intent(in) :: plan
  integer,   intent(in) :: Nx, Ny, Nz
  complex*16            :: c(0:Nx/2, 0:Ny-1, 0:Nz-1) !CAUTION "/2"!
  real*8,    intent(out):: r(0:Nx-1, 0:Ny-1, 0:Nz-1)
  integer,   intent(in) :: flags
  integer ix, iy, iz, icon
  call DM_V3DRCF(c, 2*(Nx/2+1), Nx, Ny, Nz, 1, -1, ICON)
  do iz = 0, Nz-1
     do iy = 0, Ny-1
        do ix = 0, Nx-1
           if (mod(ix,2)==0) then
              r(ix,iy,iz) =  dble(c(ix/2,iy,iz))
           else
              r(ix,iy,iz) = aimag(c(ix/2,iy,iz))
           end if
        end do
     end do
  end do
end subroutine dfftw_plan_dft_c2r_3d

after:

subroutine dfftw_plan_dft_c2r_3d(plan, Nx, Ny, Nz, c, r, flags)
  implicit none
  integer*8, intent(in) :: plan
  integer,   intent(in) :: Nx, Ny, Nz
  complex*16            :: c(0:Nx/2, 0:Ny-1, 0:Nz-1) !CAUTION "/2"!
  real*8,    intent(out):: r(0:Nx-1, 0:Ny-1, 0:Nz-1)
  integer,   intent(in) :: flags
  integer ix, iy, iz, icon
  call DM_V3DRCF(c, 2*(Nx/2+1), Nx, Ny, Nz, 1, -1, ICON)
  do iz = 0, Nz-1
     do iy = 0, Ny-1
        do ix = 0, Nx-1, 2
           r(ix,iy,iz) =  dble(c(ix/2,iy,iz))
        end do
        do ix = 1, Nx-1, 2
           r(ix,iy,iz) = aimag(c(ix/2,iy,iz))
        end do
     end do
  end do
end subroutine dfftw_plan_dft_c2r_3d

この議論は賞味期限が切れたので、アーカイブ化されています。 新たにコメントを付けることはできません。
  • それを一番外に出しておけば、「1つの条件判定内で、ループ」になるから、ずっと最適化しやすくなると思うんだが?

    --
    fjの教祖様
    • コメントありがとうございます.
      やりたいことは,配列をごそっとコピーすることです.
      ただし,Nxが奇数のときに端が余るので,そこを気にしないといけません.
      CとFortranとでは配列のメモリへの格納の順番みたいなモノがちがいます.
      Fortranでは,ここのixのほうがメモリ上で横に並びます.
      それでも条件分岐をループの外にした方が得なのかなぁ,ってのが疑問です.
      --
      love && peace && free_software
      t-nissie
      • やりたいことは,配列をごそっとコピーすることです.

        たぶん最大のポイントは、これがコンパイラに伝わっていない、という点でしょう。
        その理由は、奇数と偶数で、呼び出す関数が違うという形で書かれていること。そして(これは予想ですが)、おそらくその関数の実態がどのような存在なのか、この部分をコンパイルしているときにはノーヒントだ、というのが問題。

        関数コールのたびに Cache やメモリアクセスに関する予測は「予測不能」になってしまう。ループの最も内側で if 文を用意して、それぞれの分岐結果が「予測不能」なブロックで構成されていると、最適化予測はほとんど不可能になります。結果、安全サイドに倒さざるを得なくなる。

        最も内側のループを同一性質でできたループ2つに分けると速度が上がるなら、ix によるループをいちばん外側に出すとさらに速度は上がると思います。

        でも、それ以前に、ループの一番内側にいる関数2つが、そもそも何なのかをコンパイラに教える方法がないか、考えたほうがいいのは事実です。両方の関数をインライン展開できるだけのヒントがあれば(たとえコンパイル時にインライン展開していないとしても)、それなりの「配慮」ってやつをしてくれるコンパイラは多いです。

        --
        fjの教祖様
  • by Anonymous Coward on 2011年10月16日 18時22分 (#2035419)

    キャッシュ容量云々よりも、少し前の分岐予測なら一番嫌いな分岐先が毎回変わるパターンになっているからです。

    #1回前の履歴だけしか保持していない場合、毎回ミスするパターンです

    in-order処理で分岐予測が無い場合でも、mod命令分だけ速くなるはずです。

  • by Anonymous Coward on 2011年10月16日 23時33分 (#2035531)
    do ix = 0, Nx-2, 2
                          r(ix,iy,iz) = dble(c(ix/2,iy,iz))
                          r(ix+1,iy,iz) = aimag(c(ix/2,iy,iz))
                    end do
                    if ( ix < Nx ) then
                          r(ix,iy,iz) = dble(c(ix/2,iy,iz))
                    end if

    Nxは偶数って制約ありそうなので、最後のif文は使われないと思いますが念のため。
    (ix判定が不安なら↓みたくNx判定でも可。但しNx==0でエラーですがw)

                          if (mod(Nx,2)==0) then
                                r(Nx-1,iy,iz) = dble(c((Nx-1)/2,iy,iz))
                          end if
typodupeerror

目つきのヤバい少年がナイフをシュッ・シュッと振り回しながら街を徘徊している情景が目に浮かんだ -- あるセキュリティ専門家

読み込み中...