Этот пример умножает две матрицы A
и B
при помощи cuBLAS библиотеки. MATLAB® реализация Общего Матричного Умножения матриц (GEMM):
function [C] = blas_gemm(A,B) C = zeros(size(A)); C = A * B; end
Когда вы генерируете 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 реализациями библиотеки.