3

私はCUDAプログラミングにまったく慣れていません。うまくいけば、単純なソースで拡散方程式をモデル化するCUDAサブルーチンがあります。

attributes(global) subroutine diff_time_stepper(v,diffconst)


real*8 :: v(:,:)
real*8 :: diffconst

real*8 :: vintermed
integer :: i,j,m
integer :: nx, ny

nx=256
ny=256

i=(blockIdx%x-1)*blockDim%x+threadIdx%x
j=(blockIdx%y-1)*blockDim%y+threadIdx%y

if (i<nx .and. j<ny .and. i>1 .and. j>1) then
  vintermed=v(i,j)+diffconst*(v(i-1,j)-2.*v(i,j)+v(i+1,j)+v(i,j-1)-2.*v(i,j)+v(i,j+1))
  v(i,j)=vintermed
! add a source for the heck of it
  if (i==64 .and. j==64) v(i,j)=v(i,j)+1
endif


end subroutine

私の質問:このルーチンは機能しているようで、妥当な結果が得られます(期待したほど速く実行されていなくても)。しかし、ここに「後方依存関係」がありますか?特に、vintermは複数のvを含む関数によって設定され、次にvはvtinermと等しく設定されます。そして、この計算の後にv(64,64)が設定されます。これらの潜在的な問題はありますか?より一般的には、CUDAのプログラミング方法について多くの議論を見つけましたが、この後方依存の問題についてはほとんど議論を見つけていません。これは私にとって最も重要だと思われます。誰かが私にこれについての良い議論を指摘できますか?ありがとう。

4

1 に答える 1

2

そうです。さまざまなスレッドがvを読み込み、更新しています。一般に、予測できない順序です(ただし、同じブロックのワープ内のスレッドの動作について言えることもあります)。これは当てはまります(注意点が異なります)。たとえば、OpenMPなどのお気に入りのCPUベースのスレッドフレームワークを使用します。

拡散の問題は、ほとんどの場合よりも堅牢です。たとえば、Gauss SidelまたはJacobiの反復では、値を読み取る前に更新値を明示的に使用しますが、スレッドごとに異なるタイムステップの値があるため、問題が発生します。特に、更新される前にv(64,64)を読み込んだり読み取らなかったりすると、一般に、ソース周辺のピークの形状に一貫性がなくなります。

以下を読んだ後にスレッドを同期することにより、これがブロックで発生しないことを確認して実行しました。

...
real*8 :: left, right, up, down, centre

nx=256
ny=256

i=(blockIdx%x-1)*blockDim%x+threadIdx%x
j=(blockIdx%y-1)*blockDim%y+threadIdx%y

if (i<nx .and. j<ny .and. i>1 .and. j>1) then
  left  = v(i-1,j)
  right = v(i+1,j)
  up    = v(i,  j+1)
  down  = v(i,  j-1)
  centre= v(i,j)
endif
call syncthreads()

if (i<nx .and. j<ny .and. i>1 .and. j>1) then
  v(i,j) = centre + diffconst*(left+right+up+down-4.*centre)
  if (i==64 .and. j==64) v(i,j)=v(i,j)+1
endif

しかし、これは問題をスレッドの境界ではなくブロックの境界に押しやるだけです。ブロックが読み取っている/更新している順序はまだわかりませんv。ただし、ブロックを同期する唯一の方法は、カーネルの終わりを使用することです。

これを回避する方法はいくつかありますが、すべて、より多くのメモリまたはより少ない並列処理を使用する必要があります。そのための1つの方法は、全員にvoldから読み取ってもらい、vnewを更新することです。そうすれば、全員が古いアレイから読み取って新しいアレイを更新するだけで、同期の問題は発生しません。次に、タイムステップごとに古いものと新しいものの意味を切り替えるだけなので、奇数のタイムステップごとにvoldが読み込まれ、vnewが出力され、偶数のタイムステップごとに逆になります。

于 2012-05-22T16:12:34.053 に答える