2

Ron Farberのコードの動作を理解するのに助けが必要です:http ://www.drdobbs.com/parallel/cuda-supercomputing-for-the-masses-part/208801731?pgno = 2

共有メモリを使用すると、非共有メモリバージョンよりもパフォーマンスが向上することを理解していません。つまり、インデックス計算ステップをさらにいくつか追加し、別のRd / Wrサイクルを追加して共有メモリにアクセスする場合、グローバルメモリのみを使用するよりもこれをどのように高速化できますか?どちらの場合も、同じ数またはRd/Wrサイクルがグローバルメモリにアクセスします。データは、カーネルインスタンスごとに1回だけアクセスできます。データは引き続きグローバルメモリを使用して出入りします。カーネルインスタンスの数は同じです。レジスタ数は同じように見えます。処理ステップを追加すると、どのように高速化できますか。(プロセスステップを差し引くことはありません。)基本的に、より多くの作業を行っており、より速く完了しています。

共有メモリアクセスはグローバルよりもはるかに高速ですが、ゼロ(または負)ではありません。私は何が欠けていますか?

「スロー」コード:

__global__ void reverseArrayBlock(int *d_out, int *d_in) {
int inOffset  = blockDim.x * blockIdx.x;
int outOffset = blockDim.x * (gridDim.x - 1 - blockIdx.x);
int in  = inOffset + threadIdx.x;
int out = outOffset + (blockDim.x - 1 - threadIdx.x);
d_out[out] = d_in[in];
}

「高速」コード:

__global__ void reverseArrayBlock(int *d_out, int *d_in) {
extern __shared__ int s_data[];

int inOffset  = blockDim.x * blockIdx.x;
int in  = inOffset + threadIdx.x;

// Load one element per thread from device memory and store it
// *in reversed order* into temporary shared memory
s_data[blockDim.x - 1 - threadIdx.x] = d_in[in];

// Block until all threads in the block have written their data to shared mem
__syncthreads();

// write the data from shared memory in forward order,
// but to the reversed block offset as before
int outOffset = blockDim.x * (gridDim.x - 1 - blockIdx.x);
int out = outOffset + threadIdx.x;
d_out[out] = s_data[threadIdx.x];
}
4

3 に答える 3

6

初期のCUDA対応デバイス(計算能力<1.2)は、「遅い」バージョンのd_out[out]書き込みを合体した書き込みとして扱いませんでした。これらのデバイスは、ハーフワープのi番目のスレッドがi番目のワードにアクセスする「最も良い」場合にのみメモリアクセスを合体させます。その結果、1つのメモリトランザクションだけでなく、ハーフワープごとにd_out[out]書き込みを処理するために16のメモリトランザクションが発行されます。

計算機能1.2以降、CUDAでのメモリ合体のルールははるかに緩和されました。その結果、「遅い」バージョンでのd_out [out]書き込みも合体し、共有メモリをスクラッチパッドとして使用する必要がなくなります。

コードサンプルのソースは、2008年6月に作成された記事「CUDA、大衆向けスーパーコンピューティング:パート5」です。コンピューティング機能1.2を備えたCUDA対応デバイスは、2009年に市場に登場しただけなので、記事の執筆者は明確に話しました。計算能力が1.2未満のデバイスについて。

詳細については、 『NVIDIA CUDA Cプログラミングガイド』のセクションF.3.2.1を参照してください。

于 2012-08-13T19:37:46.910 に答える
0

グローバル メモリ アクセスを見ると、遅いコードは順方向に読み取り、逆方向に書き込みます。高速コードは、前方への読み取りと書き込みの両方を行います。キャッシュ階層が何らかの方法でグローバルメモリに降順で(より高いメモリアドレスに向かって)アクセスするように最適化されているため、高速コードの方が高速であると思います。

CPU は投機的なフェッチを行い、プログラムがデータに触れる前に、より高いメモリ アドレスからキャッシュ ラインを埋めます。GPUでも同様のことが起こるかもしれません。

于 2012-08-13T19:23:03.793 に答える
0

これは、共有メモリがコンピューティング ユニットに近いためです。そのため、レイテンシとピーク帯域幅がこの計算のボトルネックにはなりません (少なくとも行列乗算の場合)。

しかし、最も重要な理由は、タイル内の多くの数値が多くのスレッドによって再利用されていることです。したがって、グローバルからアクセスすると、それらの番号を複数回取得しています。それらを共有メモリに一度書き込むと、無駄な帯域幅の使用がなくなります

于 2012-08-13T18:21:20.127 に答える