使用共享存储器对三维阵列的一维进行求和

时间:2012-04-01 12:47:05

标签: c cuda gpu gpu-programming

我需要进行如下计算:A [x] [y] = sum {从z = 0到z = n} {B [x] [y] [z] + C [x] [y] [z ]},其中矩阵A的维度为[height] [width],矩阵为B,C的维度为[height] [width] [n]。

使用以下内容将值映射到内存:

index = 0;
for (z = 0; z<n; ++z)
    for(y = 0; y<width; ++y)
        for(x = 0; x<height; ++x) {
            matrix[index] = value;
            index++;
        }

我想每个块计算一个总和,因为每个块都有自己的共享内存。为了避免数据竞争,我使用atomicAdd,如下所示:

全局内存中的部分代码:

dim3 block (n, 1, 1);
dim grid (height, width, 1);

内核:

atomicAdd( &(A[blockIdx.x + blockIdx.y*gridDim.y]), 
           B[blockIdx.x + blockIdx.y*gridDim.y+threadIdx.x*blockDim.x*blockDim.y] 
           + C[blockIdx.x + blockIdx.y*gridDim.y+threadIdx.x*blockDim.x*blockDim.y] );

我想使用共享内存来计算总和,然后将此结果复制到全局内存中。

我不知道如何使用共享内存来完成该部分。在每个块的共享内存中将只存储一个数字(求和结果)。如何将此数字复制到全局内存中的矩阵中的正确位置?

1 个答案:

答案 0 :(得分:3)

您可能不需要共享内存或原子内存访问来执行您要求的求和。如果我已正确理解这一点,那么您的数据按列主顺序排列,因此逻辑运算是在输出矩阵中每个矩阵条目有一个线程,并让每个线程遍历输入矩阵的z轴,并在它们运行时求和。这个内核可能看起来像:

__global__ void kernel(float *A, const float *B, const float *C, 
        const int width, const int height, const int n)
{
    int tidx = threadIdx.x + blockDim.x * blockIdx.x;
    int tidy = threadIdx.y + blockDim.y * blockIdx.y;

    if ( (tidx < height) && (tidy < width) ) {
        int stride = width * height;
        int ipos = tidx + tidy * height;

        float * oval = A + ipos;
        float sum = 0.f;
        for(int z=0; z<n; z++, ipos+=stride) {
            sum += B[ipos] + C[ipos];
        }
        *oval = sum;
    }
}

对于width * height >= n的列主要数据,此方法应该是最佳的。使用共享内存没有性能优势,也没有必要使用原子内存操作。如果你遇到width * height << n问题,那么每次求和尝试逐块并行减少可能是有意义的。但是你没有说明问题的典型尺寸是什么。如果您的问题更像是后者,请发表评论,我可以在答案中添加基于缩减的示例内核。