[英]CUDA: Shift arrays on shared memory
我试图将扁平的2D矩阵加载到共享内存中,沿x移位数据,沿y回写到全局内存移位。 因此输入数据沿x和y移动。 我有的:
__global__ void test_shift(float *data_old, float *data_new)
{
uint glob_index = threadIdx.x + blockIdx.y*blockDim.x;
__shared__ float VAR;
__shared__ float VAR2[NUM_THREADS];
// load from global to shared
VAR = data_old[glob_index];
// do some stuff on VAR
if (threadIdx.x < NUM_THREADS - 1)
{
VAR2[threadIdx.x + 1] = VAR; // shift (+1) along x
}
__syncthreads();
// write to global memory
if (threadIdx.y < ny - 1)
{
glob_index = threadIdx.x + (blockIdx.y + 1)*blockDim.x; // redefine glob_index to shift along y (+1)
data_new[glob_index] = VAR2[threadIdx.x];
}
对内核的调用:
test_shift <<< grid, block >>> (data_old, data_new);
和网格和块(blockDim.x等于矩阵宽度,即64):
dim3 block(NUM_THREADS, 1);
dim3 grid(1, ny);
我无法实现它。 有人可以指出这有什么问题吗? 我应该使用跨步索引还是偏移量?
VAR
不应该被声明为共享,因为在当前形式中,当您从全局内存加载时,所有线程都会遍历彼此的数据: VAR = data_old[glob_index];
。
当你访问VAR2[threadIdx.x + 1]
,你也有一个越界访问,所以你的内核永远不会完成(取决于设备的计算能力 - 1.x设备没有严格检查共享内存访问)。
您可以通过检查所有CUDA函数调用的返回码来检测后者是否有错误。
共享变量由单个块中的所有线程共享。 这意味着您没有blockDim.y对共享变量的补充,但每个块只有一个complect。
uint glob_index = threadIdx.x + blockIdx.y*blockDim.x;
__shared__ float VAR;
__shared__ float VAR2[NUM_THREADS];
VAR = data_old[glob_index];
if (threadIdx.x < NUM_THREADS - 1)
{
VAR2[threadIdx.x + 1] = VAR; // shift (+1) along x
}
这指示块中的所有线程将数据写入单个变量(VAR)。 接下来,您没有同步,并在第二个分配中使用此变量。 这将有未定义的结果,因为来自第一个warp的线程正在读取此变量,而来自第二个warp的线程仍在尝试在那里写入某些内容。 您应该将VAR更改为本地,或者为块中的所有线程创建共享内存变量数组。
if (threadIdx.y < ny - 1)
{
glob_index = threadIdx.x + (blockIdx.y + 1)*blockDim.x;
data_new[glob_index] = VAR2[threadIdx.x];
}
在VAR2 [0]中你仍然有一些垃圾(你从来没有写过)。 threadIdx.y在您的块中始终为零。
并避免使用uints。 他们有(或曾经有)一些性能问题。
实际上,对于这样简单的任务,您不需要使用共享内存
__global__ void test_shift(float *data_old, float *data_new)
{
int glob_index = threadIdx.x + blockIdx.y*blockDim.x;
float VAR;
// load from global to local
VAR = data_old[glob_index];
int glob_index_new;
// calculate only if we are going to output something
if ( (blockIdx.y < gridDim.y - 1) && ( threadIdx.x < blockDim.x - 1 ))
{
glob_index_new = threadIdx.x + 1 + (blockIdx.y + 1)*blockDim.x;
// do some stuff on VAR
} else // just write 0.0 to remove garbage
{
glob_index_new = ( (blockIdx.y == gridDim.y - 1) && ( threadIdx.x == blockDim.x - 1 ) ) ? 0 : ((blockIdx.y == gridDim.y - 1) ? threadIdx.x : (blockIdx.y)*blockDim.x );
VAR = 0.0;
}
// write to global memory
data_new[glob_index_new] = VAR;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.