0

CUDA カーネルで printf を使用して観察した動作がわかりません。誰かがこれに光を当てることができますか? これが正常な場合、それはなぜですか?カーネル内で変更 (デバッグ) される前にデータを確実に印刷する方法はありますか?

コードは次のとおりです。

~>more *
::::::::::::::
Makefile
::::::::::::::
all:
    nvcc -o WTF.cu.o -arch=sm_21 -c WTF.cu
    g++ -o WTF.exe -I/usr/local/cuda/include WTF.cpp WTF.cu.o -L/usr/local/cuda/lib64 -lcuda -lcudart
::::::::::::::
WTF.cpp
::::::::::::::
#include <iostream> // cout
#include <cstdlib>  // rand, srand

#include <cuda_runtime_api.h> // cudaXXX
void PrintOnGPU ( unsigned int const iDataSize, int * const iopData );

using namespace std;

int main ()
{
  // Allocate and initialize CPU data
  unsigned int dataSize = 4;
  srand ( time ( NULL ) ); // Random seed
  int * pCPUData = ( int * ) malloc ( sizeof ( int ) * dataSize );
  for ( unsigned int i = 0; i < dataSize; i++ ) { pCPUData[i] = rand () % 100; cout << "CPU : " << pCPUData[i] << endl; }

  // Print from GPU
  int * pGPUData = NULL;
  cudaMalloc ( ( void ** ) &pGPUData, dataSize * sizeof ( int ) );
  cudaMemcpy ( pGPUData, pCPUData, dataSize * sizeof ( int ), cudaMemcpyHostToDevice );
  PrintOnGPU ( dataSize, pGPUData );

  // Get out
  cudaFree ( pGPUData );
  if ( pCPUData ) { free ( pCPUData ); pCPUData = NULL; }
  return 0;
}
::::::::::::::
WTF.cu
::::::::::::::
#include "stdio.h"

__global__ void WTF ( unsigned int const iDataSize, int * const iopData )
{
  if ( iDataSize == 0 || !iopData ) return;

  // Don't modify : just print
  unsigned long long int tIdx = blockIdx.x * blockDim.x + threadIdx.x; // 1D grid
  if ( tIdx == 0 )
  {
    for ( unsigned int i = 0; i < iDataSize; i++ )
      printf ( "GPU : %i \n", iopData[i] );
  }
  __syncthreads();

  // Modify
  // iopData[tIdx] = 666; // WTF ?...
}

void PrintOnGPU ( unsigned int const iDataSize, int * const iopData )
{
  WTF<<<2,2>>> ( iDataSize, iopData );
}

そして、予想通り、100 を超える値は得られません (cpp ファイルの 15 行目: rand () % 100):

~>make; ./WTF.exe
nvcc -o WTF.cu.o -arch=sm_21 -c WTF.cu
g++ -o WTF.exe -I/usr/local/cuda/include WTF.cpp WTF.cu.o -L/usr/local/cuda/lib64 -lcuda -lcudart
CPU : 38
CPU : 73
CPU : 28
CPU : 82
GPU : 38 
GPU : 73 
GPU : 28 
GPU : 82 

ここで、cu ファイル (iopData[tIdx] = 666) の 17 行目のコメントを外します。すべての値を 666 (つまり 100 以上) に変更します。CUDA カーネルでデータを変更する前に、4 つのデータ (cpp ファイルで dataSize = 4)、2 X 2 グリッド、および __syncthreads () があるため、変更されたデータを決して印刷しないでください。ただし、これを取得します(変更されたデータを値666で印刷):

 ~>make; ./WTF.exe
nvcc -o WTF.cu.o -arch=sm_21 -c WTF.cu
g++ -o WTF.exe -I/usr/local/cuda/include WTF.cpp WTF.cu.o -L/usr/local/cuda/lib64 -lcuda -lcudart
CPU : 29
CPU : 72
CPU : 66
CPU : 90
GPU : 29 
GPU : 72 
GPU : 666 
GPU : 666 

これらの 666 が表示される理由がわかりません。この動作が正常である場合、それはなぜですか?

FH

4

1 に答える 1

3

これは、2 つのスレッドブロックを起動しているためです。これらのスレッドブロックは、任意の順序で同時または順次に実行できます。

問題のある行のコメントを外したとします。ここで、スレッドブロック 1 が最初に実行され、スレッドブロック 0 の前に完了するとします。その後、スレッドブロック 0 が実行されます。しかし、スレッドブロック 0 が印刷を行っており、4 つの値すべてを印刷しています。したがって、以前にスレッドブロック 1 から 666 までに設定された値は、スレッドブロック 0 によって出力されます。

スレッドブロック 0 が最初に実行された場合、これは発生しません。したがって、最初の 2 つの GPU 値が 666 としてリストされることはなく、最後の 2 つ (スレッドブロック 1 から発生) のみが表示されると推測されます。また、スレッドの数に関係なく (少なくとも投稿されたカーネル コードを使用して)、1 つのブロックのみを起動した場合は、決して表示されません。

__syncthreads()また、それがデバイス全体の同期であると考えると混乱するかもしれません. そうではない。これは、スレッドブロック内のスレッドに対してのみバリアとして機能します。個別のスレッドブロック間の同期はありません。

于 2013-05-13T22:50:33.250 に答える