cuda子矩阵

时间:2012-03-29 09:25:33

标签: cuda gpgpu

问题:

我有4个矩阵(64x64)的单精度数。需要做如下计算:

R = A * sin(B) + C * cos(D)

主意:

加快计算使用共享内存。由于每个线程块都有(在我的GPU的情况下)16KB共享内存并且float的大小为4,因此可以在共享内存中存储4000个浮点数。因此,对于每个矩阵,使用1000个元素,每个维度为31个元素。

因此每个矩阵应分成16个子矩阵(16x16)。

dim3 dimBlock(16, 16, 1)
dim3 dimGrid(4, 4, 1)

内核:

int Tx = threadIdx.x;
int Ty = threadIdx.y;

int Bx = blockIdx.x;
int By = blockIdx.y;

int idx = Bx * blockDim.x + Tx;
int idy = By * blockDim.y + Ty;

__shared__ float s_A[16*16];
__shared__ float s_B[16*16];
__shared__ float s_C[16*16];
__shared__ float s_D[16*16];

// I am not sure how to write this part

s_A[(Tx * blockDim.x + Ty + By) + Bx] = A[idx * 64 + idy];
s_B[(Tx * blockDim.x + Ty + By) + Bx] = B[idx * 64 + idy];
s_C[(Tx * blockDim.x + Ty + By) + Bx] = C[idx * 64 + idy];
s_D[(Tx * blockDim.x + Ty + By) + Bx] = D[idx * 64 + idy];

R[idx * 64 + idy] = s_A[(Tx * blockDim.x + Ty + By) + Bx] * sin(s_B[(Tx * blockDim.x + Ty + By) + Bx]) + s_C[(Tx * blockDim.x + Ty + By) + Bx] * cos(s_D[(Tx * blockDim.x + Ty + By) + Bx]);

如何将原始矩阵分配给子矩阵,以便每个块都有自己的4个子矩阵并对其进行计算。

2 个答案:

答案 0 :(得分:5)

除非我误解了您的问题,否则您不需要也不应该使用共享内存进行此操作。共享内存对于在同一块内的线程之间共享和重新生成数据以及促进合并的内存访问非常有用。您的操作似乎不需要这些东西正常工作。以你建议的方式使用共享内存可能更慢而不是直接从全局内存中读取。此外,因为您只关心元素操作,所以内核的索引方案可以大大简化 - ABCD这一事实因为我理解你的问题,所以“矩阵”与计算无关。

因此,内核的近乎最佳版本可以像

一样编写
__global__ void kernel(const float *A, const float *B, const float *C, 
                        const float *D, const int n, float *R)
{
    int tidx = threadIdx.x + blockIdx.x * blockDim.x;
    int stride = blockDim.x * gridDim.x;

    while(tidx < n) {
        R[tidx] = A[idx] * sinf(B[idx]) + C[idx]*cosf(D[idx]);
        tidx += stride
    }
}

在此代码中,您将启动尽可能多的块以达到GPU的峰值吞吐量,并且如果阵列的大小超过您拥有的最佳1D网格的大小,则每个线程将处理多个输入/输出值推出。当然,如果你只处理4096个元素,那么这是非常有用的 - 可能大约2个数量级太小而无法从使用GPU中获得任何好处。

答案 1 :(得分:1)

你有一个问题,你的操作/传输比率是1阶。由于线程和全局内存之间的带宽瓶颈而没有办法,你可能很难从GPU获得任何合适的速度。减少那个。

当从全局内存中重复调用某些数据时,共享内存解决方案通常是最佳的。不是从低带宽,高延迟的全局内存中重复加载这些数据,而是从那里加载一次,然后从更高带宽,更低延迟的共享内存执行后续加载。注意,更高更低,而不是。使用共享内存仍然存在性能损失。

根据您的情况,由于元素不会从全局内存中多次调用,因此将它们存储在共享内存中只会增加共享内存使用带来的带宽限制和延迟。因此,实际上,此解决方案只会增加从共享内存到数据加载的访问延迟。

现在,如果您要执行多个计算,并且其中也使用了一些这些矩阵,那么将它们组合到一个内核中可能会提高速度,因为您可以为整个事物加载一次而不是每次操作一次。如果情况并非如此,并且您无法提高操作/传输率,那么您将很难获得一些不错的速度,并且最好不要在CPU上进行这些计算。

你甚至可以通过CPU上的多线程获得一些不错的结果。