我不理解我在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
答案 0 :(得分:2)
这是因为您正在启动2个线程块,并且这些线程块可以以任何顺序执行,同时或按顺序执行。
假设您没有注释麻烦的线条。现在假设线程块1首先运行并在线程块0之前完成。然后线程块0运行。但是threadblock 0正在进行打印,并且它正在打印所有4个值。因此,先前由线程块1到666设置的值由线程块0打印出来。
如果线程块0首先运行,则不会发生这种情况,相应地我的猜测是你永远不会看到列为666的前2个GPU值,只有最后2个(从线程块1发出)。如果你只启动一个块,你也永远不会看到它,无论线程数量多少(至少使用发布的内核代码)。
您可能会因为__syncthreads()
是设备级同步而感到困惑。它不是。它仅作为线程块中线程的屏障。单独的线程块之间没有同步。