あなたが何をしようとしているのかは100%明確ではありません。グローバルメモリから共有メモリにデータをコピーしようとしている場合、おそらくそれは何らかの構造を持っています。たとえば、char
sやfloat
sの配列などです。次の回答は、sの配列を処理していることを前提としています(任意のデータ型char
に置き換えることができます)。char
要約:一度に32/64/128バイトに明示的にアクセスすることは考えずに、メモリアクセスを合体できるようにコードを記述してください。
通常のC/C ++などと同じように、CUDAを使用してデータにアクセスできます。個々のバイトにまで到達することもできます。プログラミングガイドが言っていることは、データにアクセスするときはいつでも、32/64/128バイトのブロックを読み取る必要があるということです。たとえば、char a[128]
取得したい場合a[17]
、GPUはからデータを取得できるようにするためにa[0]
から読み取る必要があります。これは透過的に行われます。たとえば、個々のバイトにアクセスできるようにするために、別の方法でコーディングする必要はありません。a[31]
a[17]
主な考慮事項はメモリアクセス速度です。情報バイトごとに31ジャンクバイトを読み取る必要がある場合、実効メモリ帯域幅を32分の1に削減します(つまり、さらに多くのグローバルメモリアクセスを実行する必要があります。 sloowww)!
ただし、GPUのメモリアクセスは、ブロック内のスレッド間で「合体」することができます(この質問は、合体を最適化するための妥当な開始点を提供します)。簡単に言うと、合体により、ブロック内の複数のスレッドで同時に発生するメモリアクセスを「バッチ処理」できるため、1回の読み取りのみを実行する必要があります。
これのポイントは、(単一のスレッド内ではなく)ブロック内のスレッド間で合体が発生することです。したがって、共有メモリへのコピーの場合は、次のことができます(グローバルメモリ内array
のsの配列)。char
__shared__ char shrd[SIZE];
shrd[threadIdx.x] = array[blockDim.x * blockIdx.x + threadIdx.x];
__syncthreads();
これにより、各スレッドが1バイトを共有配列にコピーします。このmemcpy操作は基本的に並行して行われ、データアクセスは合体されるため、無駄な帯域幅(または時間)はありません。
上記の戦略は、単一のスレッドを反復処理してバイトごとにコピーするよりもはるかに優れています。
配列のnバイトの各ブロックを単一のnバイトのデータ型として扱い、各スレッドにそれをコピーさせることもできます。たとえば、n == 16の場合、いくつかのキャストを実行しますuint4
__shared__ char shrd[SIZE];
((uint4*)shrd)[threadIdx.x] = ((uint4*)array)[blockDim.x * blockIdx.x + threadIdx.x];
__syncthreads();
これにより、各スレッドが一度に16バイトをコピーできるようになります。コードのそのビットに関する注記:
- 私はそれをテストまたはベンチマークしていません
- それが良い習慣かどうかはわかりません(そうでないことを強く期待します)。
- インデックスは16でスケーリングされます(たとえば
threadIdx.x == 1
、への書き込みに対応しますshrd[16],shrd[17],...,shrd[31]
)
補足として:特定のユースケースによっては、組み込みのcudaMemcpy関数が役立つ場合があります。