第 3 章 GPGPU 17
4.2 斉次更新の実装
Ψ
(
r!1,⋯,r!i′,⋯,r!N)
Ψ
(
r!1,⋯,r!i,⋯,r!N)
CPU
GPU
Update Accept / Reject Next update r!1,⋯,!
ri,⋯,! rN
( )
! ↓
r1,⋯,r!i′,⋯,! rN
( )
r!1,⋯,! ri+1,⋯,!
rN
( )
! ↓
r1,⋯,r!i+1′ ,⋯,! rN
( )
… Repeat N times! ′
r
i! ′
r
i+1φ1( )!ri′ = a1s s=1
∑
64 Θs( )r!i′⋮ φL
!′ ri
( )= aLs
s=1
∑
64 Θs( )r!i′
φ1( )!ri+1′ = a1s s=1
∑
64 Θs( )!ri+1′⋮ φL
!′ ri+1
( )= aLs
s=1
∑
64 Θs( )r!i+1′
Fig. 4.2: 逐次更新アルゴリズム
単純実装(逐次更新の換装)段階における計算の流れを Fig.4.2に示す.任意の電子位 置をCPU上で更新後(!ri →!ri$), 試行関数を構成するφj(!ri$) の再評価のために,それを得 るのに必要なデータをGPUに転送し,φj(!r$i)をGPU上で構築する.構築されたφj(!ri$) はCPUへ戻し,試行関数を構成後,更新された電子位置の棄却/採択を行い,また次の 電子位置を更新する,という逐次更新の流れになる.上述の流れにおいて,!riと !ri+1の 更新はランダムで行なわれるため無関係である.したがって,!r1から!rN までの全電子の 軌道関数φj(!r$1)からφj(!r$N) をGPU上で一度に処理する構造(斉次更新)に変更できれ ば,GPGPU並列数を逐次更新の電子数N 倍にすることが可能である.次節ではこの斉 次更新の実装について述べる.
Ψ
(
r!1′,⋯,r!i,⋯,r!N)
Ψ
(
r!1,⋯,r!i,⋯,r!N)
⋮
Ψ
(
r!1,⋯,r!i,⋯,r!N′)
Ψ
(
r!1,⋯,r!i,⋯,r!N)
CPU
GPU
Update all
Accept / Reject
!′
r1,⋯,r!i,⋯,r!N
( )
! ⋮
r1,⋯,r!i′,⋯,r!N
( )
! ⋮ r1,⋯,!
ri,⋯,r!N′
( )
! ′ r
iφ1
!′ r1
( )= a1s
s=1
∑
64 Θs( )!r1′⋮ φL
!′ r1
( )= aLs s=1
∑
64 Θs( )r!1′⋯ φ1
!′ rN
( )
= a1ss=1
∑
64 Θs( )
r!N′⋮ φL
!′ rN
( )
= aLss=1
∑
64 Θs( )
!rN′
Fig. 4.3: 斉次更新アルゴリズム
進めるために,まずは斉次更新のCPU処理版を構築し,統計誤差範囲での一致を確認の 上,斉次更新CPU版を段階的にGPUに換装した.
4.2.2 斉次更新の GPU 換装
次に斉次更新処理を以下のようにGPU上に換装した:この段階では,§4.1で行なった のと同様に,相異なる格子点sでの積算をスレッドにアサインする(スレッド内の演算は 唯一つの積算のみ).斉次更新への変更に伴い,軌道のインデックスjに加え,電子のイ ンデックスiに関する並列性が加わる.これを(j, i)という二次元構造のブロックで処理 する(→Fig.4.4).
結果がTable 5.2に示されている.スレッド数は64で,逐次更新の場合と変わらないが
ブロック数が(電子数N×軌道数L)に増加したことで,並列度が大幅に向上し,216電 子の場合,6.39倍,1536電子の場合には5.61倍の高速化が達成された.
φj
!′ r1
( )
=aj1Θ1( )
r!1′ +aj2Θ2( )
r!1′+,⋯,+aj64Θ64( )
r!1′φk
!′ r1
( )
=ak1Θ1( )
r!1′ +ak2Θ2( )
r!1′+,⋯,+ak64Θ64( )
r!1′各スレッドで処理
ブロック
…
に分割φL
( )
r!1′ =aL1Θ1!′ r1
( )
+aL2Θ2!′ r1
( )
+,⋯,+aL64Θ64!′ r1
( )
φj
!′ rN
( )
=aj1Θ1( )
!rN′ +aj2Θ2( )
r!N′ +,⋯,+aj64Θ64( )
r!N′φk
!′ rN
( )
=ak1Θ1( )
r!N′ +ak2Θ…
2( )
!rN′ +,⋯,+ak64Θ64( )
r!N′φL
!′ rN
( )
=aL1Θ1( )
!rN′ +aL2Θ2( )
r!N′ +,⋯,+aL64Θ64( )
r!N′Fig. 4.4: 斉次更新におけるブロックとスレッドの割り当て
cavc ( j, x, y, z, spin)! M×M×M! 4×4×4=64
ajs
Fig. 4.5: cavcとajsの関係
4.2.3 スレッディング構造の改変と最適化
前節までの逐次更新および斉次更新では,積和算
"64 s=1
ajsΘs(!ri) (4.2)
において,各スレッドでajsΘs(!ri)を計算し,スレッド間のリダクションにより総和が計算 された.係数ajsのデータ構造に着目し,ランダムアクセスを解消するようなスレッディ ング構造の組み換えを試みたところ,大きな性能向上を達成することが出来た:係数ajs
はcavcという配列名で,cavc(j, x, y, z, spin)の5次元配列に格納されている.jは軌道の インデックス,x, y, zは格子点のインデックス,spinは電子スピンに関するインデックス である.本研究では非偏極系を取り扱うため,スピンのインデックスは退化・消失する.
x, y, zに関する要素数はM ×M ×M で,216電子系の場合M = 60,1536電子系では
M = 50である.
グローバルメモリ上に置かれたcavc(j, x, y, z, spin)に対し,各電子位置!riを担当するス レッドは,!ri近傍の4×4×4 = 64点の格子点でのajsの値にアクセスする(→Fig.4.5).
前節までの逐次更新,および,斉次更新の実装では相異なるsがスレッドにアサインされ ているため,sを足とする連続メモリアクセスが発生するが,cavc配列はメモリ構造上,
jを足にとる1次元配列である.したがって,cavcへのアクセスはメモリアドレス上,飛 び飛びのランダムアクセスとなってしまう.この場合,§3.4で述べたとおり,レイテンシ の大きいグローバルメモリへのアクセスが大量に発生し,高速化を妨げる.これを避ける には,各スレッドが,軌道のインデックスjを足とした1次元配列cavcへの連続アクセス を構成するようにスレッディングを組み替え,コアレッシングを行なう必要がある.この 場合,相異なる軌道jがスレッドにアサインされることになる.スレッド内の演算は,あ る一つの軌道関数を構築する(4.2)式の64項の積和算となる.残されたインデックスであ
るi(電子インデックス)についてブロック化を行なった.すなわち,同一の電子インデッ
クスi を有する複数のスレッド(L本)がブロックにまとめられ処理される(→Fig.4.6).
前節までの実装ではスレッドで並列処理されていたs=1〜64の積和算は,本実装では,
各スレッドのループ内で処理される.この構造により,従来ではスレッド間で行なってい たリダクション処理の必要がなくなった.jをスレッド並列にしたことで,以前の実装で のΘs(!ri)に関する連続アクセスが失われる.しかしながら,一つのブロック(電子イン デックスiが固定)は,高々,64要素の同一のΘs(!ri)を参照するため,再利用性があり,
キャッシュによる効果が期待される:あるWarpが一度,グローバルメモリ上にあるΘs(!ri) にアクセスすると,その近傍の配列は,L1やL2キャッシュに保持され,キャッシュヒッ トが起きやすく,Θs(!ri)に関する連続アクセスの喪失はメモリアクセス遅延上の問題に はならないと期待される.
結果がTable 5.2に示されているが,この実装で最終的に216電子の場合,16.58倍,1536 電子の場合には30.67倍の高速化が達成された.
φj
( )
r!1′ =aj1Θ1( )
r!1′ +aj2Θ2( )
r!1′+,⋯,+aj64Θ64( )
r!1′φk
( )
!r1′ =ak1Θ1( )
r!1′+ak2Θ2( )
!r1′+,⋯,+ak64Θ64( )
r!1′ 各スレッド で処理ブロックに分割
…
φL
( )
r!1′ =aL1Θ1( )
!r1′ +aL2Θ2( )
r!1′+,⋯,+aL64Θ64( )
r!1′φj
!′ rN
( )
=aj1Θ1( )
r!N′ +aj2Θ2( )
r!N′ +,⋯,+aj64Θ64( )
r!N′ φk( )
r!N′ =ak1Θ1( )
!rN′ +ak2Θ…
2( )
r!N′ +,⋯,+ak64Θ64( )
r!N′φL
!′ rN
( )
=aL1Θ1( )
r!N′ +aL2Θ2( )
r!N′ +,⋯,+aL64Θ64( )
!rN′Fig. 4.6: 最適化によるブロックとスレッドの割り当て