Подтвердить что ты не робот

Переменная массива Cuda Shared Memory

Я пытаюсь объявить переменную для умножения матрицы следующим образом:

__shared__ float As[BLOCK_SIZE][BLOCK_SIZE];

Я пытаюсь сделать так, чтобы пользователь мог ввести размер матрицы для вычисления, однако это означало бы изменение BLOCK_SIZE. Я изменил его, но я получаю ошибку компилятора: "error: постоянное значение неизвестно". Я просмотрел его, и он похож на этот поток. Поэтому я попробовал:

__shared__ int buf [];

Но потом я получаю: "ошибка: неполный тип недопустим"

Спасибо, Дэн Обновление с помощью кода (в значительной степени последовало это руководство и смотрение с руководством 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;


}
4b9b3361

Ответ 1

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], а при индексировании в Bs используйте smem[BLOCK_SIZE*BLOCK_SIZE+y*BLOCK_SIZE+x]

Ответ 2

У вас есть два варианта для объявления общей памяти внутри ядра - статического или динамического. Я предполагаю, что вы делаете в данный момент, выглядит примерно так:

#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 >>>(....);

Все одинаково справедливы, хотя я лично одобряю версию шаблона, потому что он может позволить другую оптимизацию компилятора, такую ​​как автоматическое разворачивание цикла, что динамическая версия не может без дополнительной работы.

Ответ 3

Звучит правильно.

Как правило, в этом случае вам нужно что-то malloc.

Здесь есть две вещи: один C не знает о 2D-массивах (это просто массив массивов), а размеры массива должны составлять временные константы (или что-то, что компилятор может вычислить во время компиляции).

Если вы используете C99, вы можете объявить размер массива с помощью параметра функции, но поддержка C99... в лучшем случае.