2013-05-17 24 views
26

blockDimは何かを取得します。しかし、gridDimに問題があります。 Blockdimはブロックのサイズを指定しますが、gridDimは何ですか?インターネット上では、gridDim.xはx座標のブロック数を示します。Cuda gridDimとblockDim

blockDim.x * gridDim.xはどのように表示されますか?

x行にgridDim.xの値がいくつあるかわかりますか?

int tid = threadIdx.x + blockIdx.x * blockDim.x; 
double temp = a[tid]; 
tid += blockDim.x * gridDim.x; 

while (tid < count) 
{ 
    if (a[tid] > temp) 
    { 
     temp = a[tid]; 
    } 
    tid += blockDim.x * gridDim.x; 
} 

私が知っているコードは、その後tid+=blockDim.x * gridDim.x持っ0のtid開始:

は例えば、以下のコードを検討してください。今度はtidとは何ですか? CUDA Programming Guideから言い換え

答えて

59
  • blockDim.x,y,zは、スレッドの数を示しますブロックに、 特定の方向に
  • gridDim.x,y,z
  • blockDim.x * gridDim.xは(X方向、このケースでは)グリッド内のスレッドの数を与える 特定の方向に、グリッド内のブロックの数を与える

ブロックおよびグリッド変数は1,2,3次元にすることができます。 1-Dデータを処理して1-Dブロックとグリッドのみを作成するのが一般的な方法です。

特に、x次元の合計スレッド(gridDim.x * blockDim.x)がより小さく、処理したい配列のサイズがの場合、ループを作成し、スレッドのグリッドはアレイ全体を移動します。この場合、1つのループ反復を処理した後、各スレッドは次に処理されない次の場所に移動する必要があります。これはtid+=blockDim.x*gridDim.x;で与えられます。実際には、スレッドのグリッド全体がデータの1次元配列を飛び越しています。時間。このトピックは、「グリッドストライドループ」とも呼ばれ、このblog articleでさらに論じられています。

NVIDIA webinar pageで紹介されているCUDA入門Webセミナーをいくつかお試しください。例えば、これらの2:CUDA Cを用い

  • GPUコンピューティング - 入門(2010)CUDA C.概念を使用して、GPUコンピューティングの基礎に導入 は コードサンプルのウォークスルーして説明します。アドバンスト1(2010)第1レベル、グローバルメモリの最適化として 最適化技術、及び プロセッサ使用率 - 事前GPUコンピューティング 経験は、CUDA Cを用い
  • GPUコンピューティングを必要としません。概念は実際のコードを使用して説明されます 例

これらの概念をよりよく理解したい場合は、2時間もかかるでしょう。

グリッドストライドループの一般的なトピックについては、詳細はhereを参照してください。

+0

あなたの答えはより良いと言えます。+1 – alrikai

+0

@alrikai私は単純に答えにいくつかのコメントを追加していましたあなたはそれを削除しました。 (そして、後であなたは再投稿しました。)あなたが最初で、あなたの答えは大丈夫です。 –

+0

うん、私は間違ってそれを書いている途中で投稿していた。 – alrikai

37

gridDim:この変数は、グリッドの寸法が含まれています。

blockIdx:この変数には、グリッド内のブロックインデックスが含まれます。

blockDim:この変数には、ブロックのサイズが含まれます。

threadIdx:この変数には、ブロック内のスレッドインデックスが含まれます。

CUDAが持っているスレッドの階層について少し混乱しているようです。要約すると、カーネルには1グリッドがあります(私は常に3次元立方体として視覚化しています)。その要素のそれぞれはブロックであり、dim3 grid(10, 10, 2);と宣言されたグリッドは10 * 10 * 2の合計ブロックを持ちます。次に、各ブロックはスレッドの3次元立方体です。

これは、ブロックとグリッドのx-ディメンションのみを使用するということです。これは、問題のコードが行っているように見えます。これは、特に1D配列で作業している場合には重要です。その場合、あなたのtid+=blockDim.x * gridDim.x行は実際にあなたのグリッド内の各スレッドのユニークなインデックスになります。これは、blockDim.xが各ブロックのサイズになり、gridDim.xがブロックの合計数になるからです。あなたはパラメータ

dim3 block_dim(128,1,1); 
dim3 grid_dim(10,1,1); 
kernel<<<grid_dim,block_dim>>>(...); 

でカーネルを起動した場合

だから、あなたのカーネルにあなたが効果的だろうthreadIdx.x + blockIdx.x*blockDim.xを持っていた:

threadIdx.x range from [0 ~ 128)

blockIdx.x range from [0 ~ 10)

blockDim.x equal to 128

gridDim.x equal to 10

したがってthreadIdx.x + blockIdx.x*blockDim.xを計算する、あなたはによって定義された範囲内の値を有するであろう:の範囲であろうあなたのTID値を意味する[0, 128) + 128 * [1, 10)が、{0、1、2、...、1279}。 これは、スレッドをタスクにマップする場合に便利です。これは、カーネル内のすべてのスレッドに固有の識別子を提供するためです。

あなたは

int tid = threadIdx.x + blockIdx.x * blockDim.x; 
tid += blockDim.x * gridDim.x; 

を持っている場合しかし、その後、あなたは基本的にあります:tid = [0, 128) + 128 * [1, 10) + (128 * 10)を、そしてあなたのTID値は、私がどこか分からない{1280、1281、...、2559} から及ぶでしょうこれは関連性がありますが、すべてはアプリケーションとスレッドにデータをマップする方法によって異なります。このマッピングは、どのカーネルの起動にとっても非常に中心的なものであり、どのように行うべきかを決めるのはあなたです。カーネルを起動すると、グリッドとブロックのディメンションを指定すると、カーネル内のデータへのマッピングを強制する必要があります。限り、あなたは、ハードウェアの制限を超えないよう(現代カードのために、あなたはブロックごとに2^10のスレッドと2^16の最大持つことができます - スレッドごとに1ブロック)を

+2

具体的な例はとても役に立ちました。ありがとうございました。多くの人が 'gridDim'、' blockIdx'などの定義を繰り返すだけですが、その例は非常に重要です。 – cmo

+0

すみませんが、最後のフレーズでは、ブロックあたり最大2^10のスレッドと1スレッドあたり2^16-1のブロックを持つことができますが、そうであってはいけません:最大2 ^ブロックあたり10スレッド、**グリッドあたり2^16-1ブロック** – meJustAndrew

1

このソースコードでは、4つのthredsがあります。カーネル関数は10個の配列すべてにアクセスできます。どうやって?

我々は10件のスレッドの元を作成しないのはなぜ
#define N 10 //(33*1024) 

__global__ void add(int *c){ 
    int tid = threadIdx.x + blockIdx.x * gridDim.x; 

    if(tid < N) 
     c[tid] = 1; 

    while(tid < N) 
    { 
     c[tid] = 1; 
     tid += blockDim.x * gridDim.x; 
    } 
} 

int main(void) 
{ 
    int c[N]; 
    int *dev_c; 
    cudaMalloc((void**)&dev_c, N*sizeof(int)); 

    for(int i=0; i<N; ++i) 
    { 
     c[i] = -1; 
    } 

    cudaMemcpy(dev_c, c, N*sizeof(int), cudaMemcpyHostToDevice); 

    add<<< 2, 2>>>(dev_c); 
    cudaMemcpy(c, dev_c, N*sizeof(int), cudaMemcpyDeviceToHost); 

    for(int i=0; i< N; ++i) 
    { 
     printf("c[%d] = %d \n" ,i, c[i]); 
    } 

    cudaFree(dev_c); 
} 

add<<<2,5>>> or add<5,2>>> Nは10元)33×1024よりも大きい場合、我々は、スレッドの適度に小さい数を作成する必要があるため。

このソースコードはこのケースの例です。 アレイは10、uddaスレッドは4です。 10個のアレイすべてにアクセスするには、4つのスレッドのみを使用します。

cudaの詳細でthreadIdx、blockIdx、blockDim、gridDimの意味についてのページを参照してください。このソースコードで

2 * 2(ブロック*スレッド)ので、スレッドの

gridDim.x : 2 this means number of block of x 

gridDim.y : 1 this means number of block of y 

blockDim.x : 2 this means number of thread of x in a block 

blockDim.y : 1 this means number of thread of y in a block 

我々の数は、4です。

追加カーネル関数で

、我々がアクセスすることができます0、1、2、スレッドの3指標

- >tid = threadIdx.x + blockIdx.x * blockDim.x

①0+ 0×2 = 0

②1+ 0 * 2 = 1

③0+ 1 * 2 = 2

④1+ 1 * 2 = 3

どのようにトン指標4、5、6、7、8のOアクセス残り、9 カーネルのwhileループ

tid += blockDim.x + gridDim.x in while 

**最初の呼び出し**

-1ループにおける計算がある:0+ 2×2 = 4

-2ループ:4 + 2×2 = 8

-3ループ:8 + 2 * 2 = 12

(ただし、この値はながらうち、偽であります!) **カーネルの第2の呼び出し**

-1ループ:1 + 2 * 2 = 5

-2ループ:5 + 2×2 = 9

-3ループ:+ 2 9 * 2 = 13(ただし、この値が偽であります、一方アウト)カーネルの

**第コール**

-1ループ:2 + 2×2 = 6

-2ループ:6 + 2×2 = 10(これ値はfalseですが、out!)

**カーネルの第四の呼び出し**

-1ループ:3 + 2×2 = 7

-2ループ:7 + 2 * 2 = 11(!しかし、この値は、一方アウト偽)

だから、0、1、2、3、4、5、6、7、8、9のすべてのインデックスは、TID値によってアクセスすることができます。

このページを参照してください。 http://study.marearts.com/2015/03/to-process-all-arrays-by-reasonably.html 評判が低いため、画像をアップロードできません。