5

したがって、CUDAでのメモリアクセスの合体について私が持っている考えは、ワープ内のスレッドは連続したメモリアドレスにアクセスする必要があるということです。これは、複数ではなく単一のメモリトランザクション(各アドレスの値がスレッドにブロードキャストされる)のみを引き起こすためです。シリアル方式で実行されるもの。

今、私のバス幅は48バイトです。これは、各メモリトランザクションで48バイトを転送できることを意味しますよね?したがって、バスを最大限に活用するには、一度に48バイトを読み取ることができる必要があります(スレッドごとに複数のバイトを読み取ることにより、メモリトランザクションはワープによって実行されます)。ただし、仮に、一度に48バイトを読み取る単一のスレッドが同じ利点を提供するのではないでしょうか(サイズが48バイトの構造を読み取ることで一度に48バイトを読み取ることができると想定しています)。

合体に関する私の問題は、データに対して行わなければならない転置です。私はたくさんのデータを持っているので、転置には時間がかかり、できれば他の何かに使用したいと思います。

ComputeCapability2.0を使用しています。

4

2 に答える 2

9

GPUのメモリバスは単純に48バイト幅ではありません(2の累乗ではないため、非常に面倒です)。代わりに、それぞれ8バイト(64ビット)の6つのメモリチャネルで構成されます。通常、メモリトランザクションは、メモリのバーストモードを利用するために、チャネル幅よりもはるかに広くなります。適切なトランザクションサイズは64バイトから始まり、サイズ8のバーストを生成します。これは、コンピューティング機能1.xデバイスのハーフワープの16個の32ビットワードとうまく一致します。

128バイト幅のトランザクションはまだ少し高速であり、コンピューティング機能2.0(およびそれ以降)のデバイスのワープ幅の32ビットワードアクセスと一致します。キャッシュラインも128バイト幅で一致します。単一のメモリトランザクションにマップするには、これらのアクセスすべてをトランザクション幅の倍数に揃える必要があることに注意してください。

さて、あなたの実際の問題に関して、おそらく最善のことは何もせず、キャッシュにそれを分類させることです。これは、共有メモリで明示的に行うのと同じように機能しますが、キャッシュハードウェアによって行われ、コードは必要ないため、わずかに高速になります。心配する必要があるのは、各ワープが必要な32×32×4バイト=ワード幅(フロートなど)の場合は4kバイト、ダブルアクセスの場合は8kバイトになるように十分なキャッシュを使用できるようにすることだけです。これは、同時にアクティブになるワープの数を制限して、ワープが互いのキャッシュラインをスラッシングするのを防ぐことが有益な場合があることを意味します。

float2特別な最適化では、またはのようなベクトルタイプを使用する可能性もあります。これはfloat4、すべてのCUDA対応GPUに、8バイトまたは16バイトを同じスレッドにマップするロードおよびストア命令があるためです。ただし、コンピューティング機能2.0以降では、各ワープのキャッシュフットプリントがさらに増加するため、一般的な行列転置の場合にそれらを使用する利点は実際にはわかりません。

16kBキャッシュ/48kB共有メモリのデフォルト設定では、SMごとに一度に4つのワープを実行できるため(同時に他のメモリアクセスがない場合)、48kBキャッシュ/を選択するとおそらく有益です。を使用したデフォルトの16kB/48kB分割に対する16kB共有メモリ設定cudaDeviceSetCacheConfig()。新しいデバイスはより大きなキャッシュを持ち、より多くの異なる分割を提供し、48kBを超える共有メモリの使用を選択します。詳細は、リンクされたドキュメントに記載されています。

完全を期すために、コンピューティング機能3.0で導入されたワープシャッフル命令により、キャッシュや共有メモリを経由せずにワープ内でレジスタデータを交換できることにも言及します。詳細については、CUDACプログラミングガイドの付録B.22を参照してください。
(この付録がないバージョンのプログラミングガイドが存在することに注意してください。したがって、コピーに付録B.13が別のものである場合は、提供されているリンクからリロードしてください)。

于 2012-09-25T19:56:12.320 に答える
7

あなたが述べたように、合体の目的のために、ワープアクセスの隣接する場所にある32スレッドを作成することに焦点を当てる必要があります。できれば32バイトまたは128バイトも整列させてください。それ以外は、DRAMメモリへの物理アドレスバスについて心配する必要はありません。メモリコントローラは、それぞれ64ビット幅のほとんど独立したパーティションで構成されています。ワープから出てくる合体したアクセスは、メモリコントローラーによって可能な限り迅速に満たされます。intまたはfloatにアクセスするフルワープ(32スレッド)の単一の合体アクセスでは、とにかく128バイトを取得する必要があります。つまり、DRAMへの物理バスでの複数のトランザクションです。キャッシュモードで操作している場合、とにかく、一度に128バイト未満のグローバルメモリへの要求の粒度を実際に制御することはできません。

1つのトランザクションで1つのスレッドに48バイトなどを要求させることはできません。データ構造全体に一度にアクセスしていると思われる場合は、cコードレベルでも、マシンコードレベルでは、一度に32ビットまたは64ビットを読み取る命令に変換されます。

一度に128バイトのキャッシュ制限がコードにペナルティを課していると思われる場合は、キャッシュなしモードで実行してみてください。これにより、グローバルメモリ要求の粒度が一度に32バイトに減少します。アクセスパターンが分散している(十分に合体していない)場合は、このオプションを使用するとパフォーマンスが向上する可能性があります。

于 2012-09-25T19:34:29.603 に答える