0

単純な Cuda カーネルにあるバグを理解するのに苦労しています。エラーが表示される最小値までカーネルを縮小しました。

ポイントの数を格納するだけの「ポリゴン」クラスがあります。「ポイントを追加する」(カウンターをインクリメントするだけ) 関数があり、ポリゴンの配列内のすべてのポリゴンに 4 つのポイントを追加します。最後に、ループを使用してポイント数を更新する関数を呼び出します。このループで 1new_nbpts++回呼び出すと、期待どおりの答えが得られます。つまり、すべてのポリゴンに 4 つのポイントがあります。同じループnew_nbpts++で 2 回目の呼び出しを行うと、ポリゴンのポイント数がガベージ (4194304 ポイント) になり、正しくありません (8 を取得する必要があります)。

私が誤解しているものがあると思います。

完全なカーネル:

#include <stdio.h>
#include <cuda.h>


class Polygon {
public:
  __device__ Polygon():nbpts(0){};
  __device__ void addPt() {
    nbpts++;
  }; 
  __device__ void update() {
    int new_nbpts = 0;
    for (int i=0; i<nbpts; i++) {
        new_nbpts++;
        new_nbpts++;  // calling that a second time screws up my result
    }
    nbpts = new_nbpts;
  }

 int nbpts;
};


__global__ void cut_poly(Polygon* polygons, int N)
{
  int idx = blockIdx.x * blockDim.x + threadIdx.x;
  if (idx>=N) return;

  Polygon pol;
  pol.addPt();
  pol.addPt();
  pol.addPt();
  pol.addPt();

  for (int i=0; i<N; i++) {
    pol.update();
  }

  polygons[idx] = pol;
}



int main(int argc, unsigned char* argv[])
{
  const int N = 20; 
  Polygon p_h[N], *p_d;

  cudaError_t err = cudaMalloc((void **) &p_d, N * sizeof(Polygon));   

  int block_size = 4;
  int n_blocks = N/block_size + (N%block_size == 0 ? 0:1);
  cut_poly <<< n_blocks, block_size >>> (p_d, N);

  cudaMemcpy(p_h, p_d, sizeof(Polygon)*N, cudaMemcpyDeviceToHost);

  for (int i=0; i<N; i++)
   printf("%d\n", p_h[i].nbpts);

  cudaFree(p_d);

  return 0;
}
4

1 に答える 1

2

なぜカーネルの最後でこれを行うのですか:

  for (int i=0; i<N; i++) {
    pol.update();
  }

?

各スレッドには、次の独自のインスタンスがあることに注意してください。

ポリゴン ポール;

カーネルの最後で各スレッドの pol のインスタンスを更新したい場合は、次のことだけを行う必要があります。

pol.update();

さて、あなたの場合はどうなりますか?

update() コードに 1 つしかないとします。

new_nbpts++; 

初期化。

pol.update() を呼び出す 0 から N-1 の for ループは、反復ごとに次のようになります。

  1. new_nbpts をゼロに設定
  2. new_nbpts を合計 nbpts 回インクリメントします。
  3. nbpts の値を new_nbpts に置き換えます

これにより、nbpt が変更されないという効果があることがわかると思います。pol.update() を呼び出す for ループを N 回繰り返した後でも、nbpts の値は変更されません。

私が持っているとどうなりますか:

new_nbpts++;
new_nbpts++;

私の update() メソッドで?次に、pol.update() を呼び出すたびに、次のことを行います。

  1. new_nbpts をゼロに設定
  2. new_nbpts を合計 nbpts 回 2 ずつ増やします
  3. nbpts の値を新しい nbpts に置き換えます

うまくいけば、これがpol.update() の各呼び出しで nbptsを 2 倍にする効果があることがわかります。

ここで、各スレッドでpol.update() を N 回呼び出しているため、nbpts の開始値を N 回、つまり nbpts *2^N 倍にしています。nbpts は (この場合) 4 として開始されるため、4*2^20=4194304 となります。

このすべてについて何を求めているのかはよくわかりませんが、カーネルの最後でその for ループを実行していて、Polygon pol のすべての異なるインスタンスをそのように更新しようと考えていたのではないでしょうか。しかし、それはそれを行う方法ではありません。必要なのは単一の

pol.update();

それがあなたの意図であれば、カーネルの最後に。

于 2012-11-29T05:35:01.057 に答える