共有メモリは、静的に割り当てられ、動的に割り当てられる2つの部分に分割されます。最初の部分は、コンパイル時に計算され、各宣言は、実際の配分である - コンパイル時の情報ptxas活性化ここでそれを示しています。ここ
ptxas info : Used 22 registers, 384 bytes smem, 48 bytes cmem[0]
、我々は32
intの3
配列である384
バイトを、持っています。 (下のサンプルコードを参照)。
Keplerから共有メモリへのポインタを、別の関数に渡して、デバイスのサブ関数が別の共有メモリ宣言にアクセスできるようにすることができます。
次に、動的に割り当てられた共有メモリがあります。予約されたサイズはカーネルコール中に宣言されます。
ここでは、2つの機能のさまざまな用途の例を示します。各共有メモリ領域のポインタ値に注意してください。
__device__ void dev1()
{
__shared__ int a[32] ;
a[threadIdx.x] = threadIdx.x ;
if (threadIdx.x == 0)
printf ("dev1 : %x\n", a) ;
}
__device__ void dev2()
{
__shared__ int a[32] ;
a[threadIdx.x] = threadIdx.x * 5 ;
if (threadIdx.x == 0)
printf ("dev2 : %x\n", a) ;
}
__global__ void kernel(int* res, int* res2)
{
__shared__ int a[32] ;
extern __shared__ int b[];
a[threadIdx.x] = 0 ;
b[threadIdx.x] = threadIdx.x * 3 ;
dev1();
__syncthreads();
dev2();
__syncthreads();
res[threadIdx.x] = a[threadIdx.x] ;
res2[threadIdx.x] = b[threadIdx.x] ;
if (threadIdx.x == 0)
printf ("global a : %x\n", a) ;
if (threadIdx.x == 0)
printf ("global b : %x\n", b) ;
}
int main()
{
int* dres ;
int* dres2 ;
cudaMalloc <> (&dres, 32*sizeof(int)) ;
cudaMalloc <> (&dres2, 32*sizeof(int)) ;
kernel<<<1,32,32*sizeof(float)>>> (dres, dres2);
int hres[32] ;
int hres2[32] ;
cudaMemcpy (hres, dres, 32 * sizeof(int), cudaMemcpyDeviceToHost) ;
cudaMemcpy (hres2, dres2, 32 * sizeof(int), cudaMemcpyDeviceToHost) ;
for (int k = 0 ; k < 32 ; ++k)
{
printf ("%d -- %d \n", hres[k], hres2[k]) ;
}
return 0 ;
}
このコードは384 bytes smem
を用いptxas情報を出力し、それは、グローバルa
アレイ、DEV1方法に対する第a
アレイ、及びDEV2方法a
アレイのための第三のための1つのアレイです。合計3*32*sizeof(float)=384 bytes
。
ダイナミック共有メモリを使用してカーネルを実行する場合、32*sizeof(float)
に等しい場合、これらの3つのアレイの直後にb
へのポインタが開始されます。
EDIT: このコードによって生成されたPTXファイルは、それが方法
の本体内に定義されているエントリポイントを除い
.shared .align 4 .b8 _ZZ4dev1vE1a[128];
.shared .align 4 .b8 _ZZ4dev2vE1a[128];
.extern .shared .align 4 .b8 b[];
を静的に定義された共有メモリの宣言を保持します
:
// _ZZ6kernelPiS_E1a has been demoted
メモリの共有スペースは、PTXのドキュメントhereに定義されています210
共有(.shared)状態空間は、CTA内のスレッドがデータを共有するためのCTA単位の領域です。共有メモリ内のアドレスは、CTA内の任意のスレッドによって読み書きできます。共有変数にアクセスするには、ld.sharedとst.sharedを使用します。
実行時には詳細はありませんが、プログラミングガイドhereには、2つのミキシングの詳細はありません。
PTXコンパイル時に、コンパイラは静的に割り当てられた共有メモリの量を知ることがあります。いくつかの補足的な魔法があるかもしれません。 SASSを見て、最初の命令は、(非常にstackallocの形のように見える)静的に割り当てられた共有メモリに異なる値を割り当てる逆順でSR_LMEMHIOFF
1 IADD32I R1, R1, -0x8;
2 S2R R0, SR_LMEMHIOFF;
3 ISETP.GE.U32.AND P0, PT, R1, R0, PT;
および関数を呼び出すを使用します。
ptxasコンパイラは、すべてのメソッドを呼び出すことができる最悪の場合(メソッドの1つを使用せず、関数ポインタを使用し、b
のアドレスが変更されず、割り当てられていない共有メモリ領域は決してアクセスされない)。
最後に、einpoklumはコメントで示唆しているように、これは実験的であり、ノルム/ API定義の一部ではありません。
1.コードを書くのに感謝します。 2.この例では、配列のそれぞれに異なる名前を使用することをお勧めします(私は、後でそれを遵守するために質問を編集します)。3.私に言っているのは、純粋に経験に基づいたものです。または、PTXのドキュメントでこれを説明していますか? – einpoklum
この前提が正しいか間違っていることを示す関連するCUDA/NVIDIAのマニュアルは見つかりませんでした。私はカーネルが静的に割り当てられた共用メモリのためにどれくらいの共有メモリを予約するかを必ずしも事前に知っているわけではない、境界線* - rdc = true *の設定を試す時間がかかるかもしれません。 –