42

特に以下に関して、CUDAで共有メモリとグローバルメモリを使用する方法について混乱しています。

  • を使用するときcudaMalloc()、共有メモリまたはグローバル メモリへのポインタを取得しますか?
  • グローバル メモリはホストまたはデバイスに存在しますか?
  • どちらかにサイズ制限はありますか?
  • アクセスが早いのはどっち?
  • 共有メモリに変数を格納することは、カーネルを介してそのアドレスを渡すことと同じですか? つまり、持つ代わりに

    __global__ void kernel() {
       __shared__ int i;
       foo(i);
    }
    

    なぜ同等にしないのですか

    __global__ void kernel(int *i_ptr) {
       foo(*i_ptr);
    }
    
    int main() {
       int *i_ptr;
       cudaMalloc(&i_ptr, sizeof(int));
       kernel<<<blocks,threads>>>(i_ptr);
    }
    

グローバルメモリと共有メモリの特定の速度の問題について多くの質問がありましたが、実際にどちらをいつ使用するかの概要を網羅したものはありません.

どうもありがとう

4

3 に答える 3

56
  • cudaMalloc() を使用する場合

    ホストに戻すことができるデータを gpu に保存するには、解放されるまで存続するメモリを割り当てておく必要があります。グローバル メモリは、アプリケーションが閉じるか解放されるまで有効なヒープ スペースであり、表示されます。そのメモリ領域へのポインタを持つ任意のスレッドとブロックに。共有メモリは、カーネルのブロックが終了するまで存続するスタック空間と見なすことができ、可視性は同じブロック内のスレッドのみに制限されます。そのため、cudaMalloc を使用してグローバル メモリにスペースを割り当てます。

  • 共有メモリまたはグローバル メモリへのポインタを取得しますか?

    グローバル メモリに存在するメモリ アドレスへのポインタを取得します。

  • グローバル メモリはホストまたはデバイスに存在しますか?

    グローバル メモリはデバイス上にあります。ただし、マップされたメモリを使用して、ホスト メモリを「グローバル」メモリとして使用する方法があります。CUDA ゼロ コピー メモリに関する考慮事項を参照してください。ただし、バス転送速度の制限により、速度が遅くなる場合があります。

  • どちらかにサイズ制限はありますか?

    グローバル メモリのサイズはカードごとに異なり、なしから 32GB (V100) まであります。共有メモリは計算能力に依存しますが。コンピューティング能力 2.x 未満のものには、マルチプロセッサごとに最大 16KB の共有メモリがあります (マルチプロセッサの量はカードごとに異なります)。また、計算能力が 2.x 以上のカードには、マルチプロセッサごとに最低 48KB の共有メモリがあります。

    https://en.wikipedia.org/wiki/CUDA#Version_features_and_specificationsを参照してください

    マップされたメモリを使用している場合、唯一の制限はホスト マシンのメモリ容量です。

  • アクセスが早いのはどっち?

    生の数値に関しては、共有メモリははるかに高速です (共有メモリは最大 1.7TB/秒、グローバル メモリは最大 XXXGB/秒)。ただし、共有メモリを何かで埋めるために必要なことを行うには、通常、グローバル メモリからプルします。グローバル メモリへのメモリ アクセスが合体 (非ランダム) され、大きなワード サイズである場合、カードとそのメモリ インターフェイスに応じて、数百 GB/秒の理論上の限界に近い速度を実現できます。

    共有メモリの使用は、スレッドのブロック内で、グローバルメモリから既にプルまたは評価されたデータを再利用する必要がある場合です。そのため、グローバル メモリから再度プルする代わりに、同じブロック内の他のスレッドが参照して再利用できるように共有メモリに配置します。

    また、同時に実行できるワークグループの数に影響を与えるレジスタのプレッシャーを軽減するために、スクラッチパッドとして使用することも一般的です。

  • 共有メモリに変数を格納することは、カーネルを介してそのアドレスを渡すことと同じですか?

    いいえ、何かのアドレスを渡す場合、それは常にグローバル メモリへのアドレスです。カーネルが共有メモリをその定数に設定する定数として渡すか、必要に応じてカーネルによってプルされるグローバルメモリにアドレスを渡す場合を除き、ホストから共有メモリを設定することはできません。

于 2012-12-30T19:28:38.787 に答える
11

グローバルメモリの内容は、グリッドのすべてのスレッドに表示されます。すべてのスレッドは、グローバルメモリの任意の場所に対して読み取りと書き込みを行うことができます。

共有メモリは、グリッドのブロックごとに分離されています。ブロックのどのスレッドも、そのブロックの共有メモリに対して読み取りと書き込みを行うことができます。あるブロックのスレッドは、別のブロックの共有メモリにアクセスできません。

  1. cudaMalloc常にグローバルメモリを割り当てます。
  2. グローバルメモリはデバイス上にあります。
  3. 明らかに、すべてのメモリにはサイズ制限があります。グローバルメモリは、使用しているGPUのDRAMの合計量です。たとえば、1536 MBのDRAM、つまり1536MBのグローバルメモリを搭載したGTX460Mを使用しています。共有メモリはデバイスアーキテクチャによって指定され、ブロックごとに測定されます。コンピューティング機能1.0〜1.3のデバイスには16 KB/Block48 KB/Blockデフォルトで共有メモリがあります。
  4. 共有メモリは、グローバルメモリよりもアクセスが非常に高速です。これは、ブロックのスレッド間で共有されるローカルキャッシュのようなものです。
  5. いいえ。ホストから起動されたカーネルに渡すことができるのは、グローバルメモリアドレスのみです。最初の例では、変数は共有メモリから読み取られますが、2番目の例では、変数はグローバルメモリから読み取られます。

アップデート:

Compute Capability 7.0(Volta Architecture)のデバイスでは、次の条件が満たされている場合、ブロックあたり最大96KBの共有メモリを割り当てることができます。

  • 共有メモリは動的に割り当てられます
  • カーネルを起動する前に、動的共有メモリの最大サイズを次の関数cudaFuncSetAttributeを使用して指定します。

__global__ void MyKernel(...)
{
    extern __shared__ float shMem[];
}

int bytes = 98304; //96 KB
cudaFuncSetAttribute(MyKernel, cudaFuncAttributeMaxDynamicSharedMemorySize, bytes);

MyKernel<<<gridSize, blockSize, bytes>>>(...);
于 2012-12-30T19:25:11.107 に答える