В этом примере умножаются две матрицы A и B с помощью библиотеки cuBLAS. Реализация MATLAB ® GEneral Matrix-Matrix Multiplication (GEMM):
function [C] = blas_gemm(A,B) C = zeros(size(A)); C = A * B; end
При создании кода CUDA ® графический процессор 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 до нуля. Это ядро запускается с 2048 блоками и 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 для создания ядраКодер графического процессора не требует специальной прагматики для генерации вызовов библиотек. Существует два способа создания ядер CUDA - coder.gpu.kernelfun и coder.gpu.kernel. В этом примере мы используем coder.gpu.kernelfun pragma для создания ядер CUDA. Измененный blas_gemm функция:
function [C] = blas_gemm(A,B) %#codegen C = coder.nullcopy(zeros(size(A)); coder.gpu.kernelfun; C = A * B; end
Примечание
Для замены математических операторов и функций реализациями библиотеки cuBLAS на входные данные требуется минимальный размер (128 элементов).