Пример cuBLAS

Этот пример умножает две матрицы A и B при помощи cuBLAS библиотеки. Реализация MATLAB® Общего Матричного Умножения матриц (GEMM):

function [C] = blas_gemm(A,B)

    C = zeros(size(A));
    C = A * B;
end

Сгенерированный код CUDA

Когда вы генерируете код CUDA®, GPU Coder™ создает вызовы функции инициализировать cuBLAS библиотеку, выполнить матричные операции над матрицей и выпустить аппаратные ресурсы, которые использует cuBLAS библиотека. Следующее является отрывком сгенерированного кода CUDA.

   cublasEnsureInitialization();
  blas_gemm_kernel1<<<dim3(2048U, 1U, 1U), dim3(512U, 1U, 1U)>>>(gpu_C);
  alpha1 = 1.0;
  beta1 = 0.0;
  cudaMemcpy((void *)gpu_alpha1, (void *)&alpha1, 8ULL, cudaMemcpyHostToDevice);
  cudaMemcpy((void *)gpu_A, (void *)A, 8388608ULL, cudaMemcpyHostToDevice);
  cudaMemcpy((void *)gpu_B, (void *)B, 8388608ULL, cudaMemcpyHostToDevice);  
  cudaMemcpy(gpu_beta1, &beta1, 8ULL, cudaMemcpyHostToDevice);
  cublasDgemm(cublasGlobalHandle, CUBLAS_OP_N, CUBLAS_OP_N, 1024, 1024, 1024,
             (double *)gpu_alpha1, (double *)&gpu_A[0], 1024, (double *)&gpu_B
              [0], 1024, (double *)gpu_beta1, (double *)&gpu_C[0], 1024);
  cublasEnsureDestruction();
  cudaMemcpy((void *)C, (void *)gpu_C, 8388608ULL, cudaMemcpyDeviceToHost);

Инициализировать cuBLAS библиотеку и создать указатель на cuBLAS контекст библиотеки, функциональный cublasEnsureInitialization() вызовы cublasCreate() cuBLAS API. Это выделяет аппаратные ресурсы на хосте и устройстве.

static void cublasEnsureInitialization(void)
{
  if (cublasGlobalHandle == NULL) {
    cublasCreate(&cublasGlobalHandle);
    cublasSetPointerMode(cublasGlobalHandle, CUBLAS_POINTER_MODE_DEVICE);
  }
}

blas_gemm_kernel1 инициализирует матрицу результата C обнулять. Это ядро запускается с 2 048 блоками и 512 потоками на блок. Они блокируют и распараллеливают значения, соответствуют размеру C.

static __global__ __launch_bounds__(512, 1) void blas_gemm_kernel1(real_T *C)
{
  int32_T threadIdX;
  threadIdX = (int32_T)(blockDim.x * blockIdx.x + threadIdx.x);
  if (!(threadIdX >= 1048576)) {
    C[threadIdX] = 0.0;
  }
}

Вызовы cudaMemcpy передайте матрицы A и B с хоста на устройство. Функциональный cublasDgemm уровень 3 Основная Подпрограмма Линейной алгебры (BLAS3), который выполняет матричное умножение матриц:

C = αAB + βC

где α и β являются скалярами и A, B, и C являются матрицами, сохраненными в упорядоченном по столбцам формате. CUBLAS_OP_N средства управления транспонируют операции на входных матрицах.

Итоговые вызовы к cublasEnsureDestruction() и другой cudaMemcpy. cublasEnsureDestruction() вызовы cublasCreate() cuBLAS API, чтобы выпустить аппаратные ресурсы cuBLAS использование библиотеки. cudaMemcpy копирует матрицу результата C от устройства до хоста.

static void cublasEnsureDestruction(void)
{
  if (cublasGlobalHandle != NULL) {
    cublasDestroy(cublasGlobalHandle);
    cublasGlobalHandle = NULL;
  }
}

Подготовьте blas_gemm для создания ядра

GPU Coder требует, чтобы никакая специальная прагма не сгенерировала вызовы библиотек. Существует два способа сгенерировать ядра CUDA — coder.gpu.kernelfun и coder.gpu.kernel. В этом примере мы используем coder.gpu.kernelfun прагма, чтобы сгенерировать ядра CUDA. Модифицированный blas_gemm функция:

function [C] = blas_gemm(A,B) %#codegen
    C = coder.nullcopy(zeros(size(A));

    coder.gpu.kernelfun;
    C = A * B;
end

Примечание

Минимальный размер (128 элементов) требуется на входных данных для замены математических операторов и функций с cuBLAS реализациями библиотеки.