カードで利用可能なすべてのRAMを利用するCUDAアプリに取り組んでおり、キャッシュミスを減らすさまざまな方法を見つけようとしています。
問題領域は、解決する問題のタイプに応じて、大きな 2 次元または 3 次元のグリッドで構成されます。(興味のある方は、FDTD シミュレータです)。各要素は、「並列」配列 (つまり、ほぼ同じ次元の別の配列) の 2 つまたは 4 つの要素に依存するため、カーネルは 3 つまたは 6 つの異なる配列にアクセスする必要があります。
問題
*これが「ローカライズされすぎていない」ことを願っています。質問は自由に編集してください
3 つの配列間の関係は、次のように視覚化できます (平凡な ASCII アートで申し訳ありません)。
A[0,0] -C[0,0]- A ---- C ---- A ---- C ---- A
| | | |
| | | |
B[0,0] B B B
| | | |
| | | |
A ---- C ---- A ---- C ---- A ---- C ---- A
| | | |
| | | |
B B B B
| | | |
| | | |
A ---- C ---- A ---- C ---- A ---- C ---- A
| | | |
| | | |
B B B B[3,2]
| | | |
| | | |
A ---- C ---- A ---- C ---- A ---- C ---- A[3,3]
[2,3]
線でつながれたアイテムが結合されます。上に見られるように、A[]
は と の両方に依存しますが、B[]
とC[]
同様B[]
に のみに依存A[]
しC[]
ます。のすべてがA[]
最初のカーネルで更新され、すべてのB[]
とC[]
が 2 番目のパスで更新されます。
これらの配列を単純な 2D 配列として宣言すると、ストライド メモリ アクセスが発生します。ドメイン サイズが非常に大きい場合 (上記のグリッドでは 3x3 +- 1)、占有率とパフォーマンスの低下が発生します。
そこで、Z オーダー曲線で配列レイアウトを再配置することを考えました。
また、これらを 1 つの配列にインターリーブするのはかなり簡単です。(インターリーブの順序によっては) 特定のセルの更新に必要な要素の少なくとも半分が互いに近くにあるため、フェッチのパフォーマンスが向上するはずです。ただし、GPU が複数の配列にアクセスするときに複数のデータ ポインターを使用するかどうかは明確ではありません。もしそうなら、この想像上の利益は実際には障害になる可能性があります.
質問
テクスチャ メモリまたはcudaArray
. これが当てはまらない場合、小さなグリッドでの局所性の利点を排除するために、大きなスパンを横切るとき (高いサブディビジョン レベルで Z 曲線が右上から左下に移動するとき) にレイテンシが増加することを予期する必要がありますか?
グリッドを共有メモリに収まる小さなブロックに分割することは確かに役立つはずであり、Z オーダーによりこれはかなり簡単になります。ブロック間の境界を更新する別のカーネル パスが必要ですか? 別のカーネルを起動するオーバーヘッドは、私が期待する節約と比較して重要ですか?
2D と 1D の配列を使用することには、実際の利点はありますか? メモリは線形であると予想していますが、CUDA 文献でよく使用される 2D メモリ レイアウトの比喩に実際の意味があるかどうかはわかりません。
うわー - 長い質問です。これを読んで答えてくれてありがとう。