Cuda共享内存数组变量

时间:2012-02-08 04:36:23

标签: c cuda

我正在尝试为矩阵乘法声明一个变量,如下所示:

__shared__ float As[BLOCK_SIZE][BLOCK_SIZE];

我试图让它成为用户可以输入矩阵的大小来计算,但这意味着改变BLOCK_SIZE。我改变了它但是我收到了编译器错误:“错误:常量值未知”。我调查了它,它与thread类似。所以我试过了:

__shared__ int buf [];

但后来我得到:“错误:不允许不完整的类型”

谢谢, 担 使用代码更新(几乎遵循this guide并盯着cuda指南): 通过询问用户矩阵的大小来传递块大小。他们进入x和y。块大小仅为x,现在它必须接受与x和y相同的大小。

__global__ void matrixMul( float* C, float* A, float* B, int wA, int wB,size_t block_size)
{
    // Block index
    int bx = blockIdx.x;
    int by = blockIdx.y;

    // Thread index
    int tx = threadIdx.x;
    int ty = threadIdx.y;

    // Index of the first sub-matrix of A processed 
    // by the block
    int aBegin = wA * block_size * by;

    // Index of the last sub-matrix of A processed 
    // by the block
    int aEnd   = aBegin + wA - 1;

    // Step size used to iterate through the 
    // sub-matrices of A
    int aStep  = block_size;

    // Index of the first sub-matrix of B processed 
    // by the block
    int bBegin = block_size * bx;

    // Step size used to iterate through the 
    // sub-matrices of B
    int bStep  = block_size * wB;
    float Csub=0;
    // Loop over all the sub-matrices of A and B
    // required to compute the block sub-matrix
    for (int a = aBegin, b = bBegin; a <= aEnd; a += aStep, b += bStep) 
    {
        // Declaration of the shared memory array As 
        // used to store the sub-matrix of A

        extern __shared__ float As[];

        // Declaration of the shared memory array Bs 
        // used to store the sub-matrix of B
        extern __shared__ float Bs[];
        extern __shared__ float smem[];

        // Load the matrices from global memory
        // to shared memory; each thread loads
        // one element of each matrix
        smem[ty*block_size+tx] = A[a + wA * ty + tx];
        //cuPrintf("\n\nWhat are the memory locations?\n");
        //cuPrintf("The shared memory(A) is: %.2f\n",smem[ty*block_size+tx]);
        smem[block_size*block_size+ty*block_size+tx]  = B[b + wB * ty + tx];
        //cuPrintf("The shared memory(B) is: %.2f\n",smem[block_size*block_size+ty*block_size+tx]);
        // Synchronize to make sure the matrices 
        // are loaded
        __syncthreads();

        // Multiply the two matrices together;
        // each thread computes one element
        // of the block sub-matrix
        for (int k = 0; k < block_size; ++k)
        {

            Csub += smem[ty*block_size+k] * smem[block_size*block_size+k*block_size+tx] ;
            //cuPrintf("Csub is currently: %.2f\n",Csub);
        }
        //cuPrintf("\n\n\n");
        // Synchronize to make sure that the preceding
        // computation is done before loading two new
        // sub-matrices of A and B in the next iteration
        //cuPrintf("the results are csub: %.2f\n",Csub);
        __syncthreads();
    }
    // Write the block sub-matrix to device memory;
    // each thread writes one element
    int c = wB * block_size * by + block_size * bx;
    C[c + wB * ty + tx] = Csub;


}

3 个答案:

答案 0 :(得分:27)

extern __shared__ int buf[];

当你启动内核时,你应该以这种方式启动它;

kernel<<<blocks,threads,numbytes_for_shared>>>(...);

如果您有多个extern声明的共享:

extern __shared__ float As[];

extern __shared__ float Bs[];

这会导致As指向与Bs相同的地址。

您需要将As和B保留在1D阵列中。

extern __shared__ float smem[];

调用内核时,应使用2*BLOCK_SIZE*BLOCK_SIZE*sizeof(float)启动它。

在索引编入As时,使用smem[y*BLOCK_SIZE+x],当使用smem[BLOCK_SIZE*BLOCK_SIZE+y*BLOCK_SIZE+x]

索引到B时

答案 1 :(得分:26)

在内核中声明共享内存有两种选择 - 静态或动态。我认为你现在正在做的事情看起来像这样:

#define BLOCK_SIZE (16)

__global__ void sgemm0(const float *A, const float *B, float *C)
{
    __shared__ float As[BLOCK_SIZE][BLOCK_SIZE];

}

您希望能够轻松更改BLOCK_SIZE。

一种可能性是继续使用静态共享内存分配,但将分配大小设置为模板参数,如下所示:

template<int blocksize=16>
__global__ void sgemm1(const float *A, const float *B, float *C)
{
    __shared__ float As[blocksize][blocksize];

}
template void sgemm1<16>(const float *, const float *, float *C);

然后,您可以根据需要在编译时实例化多个不同的块大小变体。

如果要动态分配内存,请按以下方式定义:

__global__ void sgemm2(const float *A, const float *B, float *C)
{
    extern __shared__ float As[];

} 

然后将分配的大小作为参数添加到内核调用:

size_t blocksize = BLOCK_SIZE * BLOCK_SIZE;
sgemm2<<< gridDim, blockDim, sizeof(float)*blocksize >>>(....);

如果您有多个静态声明的数组,您希望用动态分配的共享内存替换它们,那么请注意每个内核只有一个动态共享内存分配,因此多个项目在(共享)内存段中退出。所以,如果你有类似的东西:

#define BLOCK_SIZE (16)

__global__ void sgemm0(const float *A, const float *B, float *C)
{
    __shared__ float As[BLOCK_SIZE][BLOCK_SIZE];
    __shared__ float Bs[BLOCK_SIZE][BLOCK_SIZE];

}

您可以将其替换为:

#define BLOCK_SIZE (16)

__global__ void sgemm3(const float *A, const float *B, float *C)
{
    extern __shared__ float buffer[];

    float *As = &buffer[0];
    float *Bs = &buffer[BLOCK_SIZE*BLOCK_SIZE];

}

并像这样启动内核:

size_t blocksize = 2 * BLOCK_SIZE * BLOCK_SIZE;
sgemm3<<< gridDim, blockDim, sizeof(float)*blocksize >>>(....);

所有这些都同样有效,虽然我个人赞成模板版本,因为它可以允许其他编译器优化,如自动循环展开,动态版本不能没有额外的工作。

答案 2 :(得分:0)

听起来不错。

通常在这种情况下,你需要malloc。

这里有两件事,一个C不知道2D数组(它只是一个数组数组),数组大小需要编译时间常数(或者编译器可以在编译时计算的东西)。

如果您使用的是C99,您可以使用该函数的参数声明数组大小,但C99支持最多只是...。