CUDA:意外的printf行为

时间:2013-05-13 22:31:18

标签: cuda

我不理解我在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文件中的第17行(iopData [tIdx] = 666):我将所有值修改为666(即大于100)。由于我在CUDA内核中修改数据之前有4个数据(csp文件中的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

1 个答案:

答案 0 :(得分:2)

这是因为您正在启动2个线程块,并且这些线程块可以以任何顺序执行,同时或按顺序执行

假设您没有注释麻烦的线条。现在假设线程块1首先运行并在线程块0之前完成。然后线程块0运行。但是threadblock 0正在进行打印,并且它正在打印所有4个值。因此,先前由线程块1到666设置的值由线程块0打印出来。

如果线程块0首先运行,则不会发生这种情况,相应地我的猜测是你永远不会看到列为666的前2个GPU值,只有最后2个(从线程块1发出)。如果你只启动一个块,你也永远不会看到它,无论线程数量多少(至少使用发布的内核代码)。

您可能会因为__syncthreads()是设备级同步而感到困惑。它不是。它仅作为线程块中线程的屏障。单独的线程块之间没有同步。