我正在尝试将对象传递给内核。该对象基本上有两个变量,一个作为输入,另一个作为内核的输出。但是当我启动内核时,输出变量不会改变。但是当我向内核添加另一个变量并将输出值分配给这个变量时,它突然适用于它们。
我在另一个线程(While loop fails in CUDA kernel)中读到,如果内核没有产生任何输出,编译器可以将内核评估为空以进行优化。
因此,我作为唯一内核参数传递的输入/输出对象可能不会被编译器识别为输出?如果这是真的。是否有一种优雅的方式(我想避免添加另一个内核参数),例如编译可以防止这种情况的选项?
这是此对象的类。
class Replica
{
public :
signed char gA[1024];
int MA;
__device__ __host__ Replica(){
}
};
这就是内核基本上是减少总和。
__global__ void sumKerA(Replica* Rd)
{
int t = threadIdx.x;
int b = blockIdx.x;
__shared__ signed short gAs[1024];
gAs[t] = Rd[b].gA[t];
for (unsigned int stride = 1024 >> 1; stride > 0; stride >>= 1){
__syncthreads();
if (t < stride){
gAs[t] += gAs[t + stride];
}
}
__syncthreads();
if (t == 0){
Rd[b].MA = gAs[0];
}
}
最后是我的主持人代码。
int main ()
{
// replicas - array of objects
Replica R[128];
for (int i = 0; i < 128; ++i){
for (int j = 0; j < 1024; ++j){
R[i].gA[j] = 2*(rand() % 2) - 1;
}
R[i].MA = 0;
}
Replica* Rd;
cudaSetDevice(0);
cudaMalloc((void **)&Rd,128*sizeof(Replica));
cudaMemcpy(Rd,R,128*sizeof(Replica),cudaMemcpyHostToDevice);
dim3 DimBlock(1024,1,1);
dim3 DimGridA(128,1,1);
sumKerA <<< DimBlock, DimGridA >>> (Rd);
cudaThreadSynchronize();
cudaMemcpy(&R,Rd,128*sizeof(Replica),cudaMemcpyDeviceToHost);
// cudaMemcpy(&M,Md,128*sizeof(int),cudaMemcpyDeviceToHost);
for (int i = 0; i < 128; ++i){
cout << R[i].MA << " ";
}
cudaFree(Rd);
return 0;
}
答案 0 :(得分:0)
根据您的缩减代码,您似乎打算每个块启动1024个线程。
在这种情况下,这是不正确的:
dim3 DimBlock(1024,1,1);
dim3 DimGridA(128,1,1);
sumKerA <<< DimBlock, DimGridA >>> (Rd);
第一个内核配置参数是网格的维。第二个参数是threadblock的维度。如果你想要每个块1024个线程,同时启动128个块,你的内核启动应如下所示:
sumKerA <<< DimGridA, DimBlock >>> (Rd);
如果在代码中添加proper cuda error checking,我预计你会看到内核启动失败,因为使用块变量(blockIdx.x)索引到128个元素的Rd
数组会索引超出数组末尾,在原始情况下。
如果修改内核中Rd
所指向的副本对象,这是外部可见状态,那么修改这些对象的任何代码都不能被优化掉#34;由编译器。
另请注意,cudaThreadSynchronize()
已弃用,而不是cudaDeviceSynchronize()
(它们具有相同的行为。)