5.1 CUBLAS

CUBLAS — реализация интерфейса программирования приложений для создания библиотек, выполняющих основные операции линейной алгебры BLAS (Basic Linear Algebra Subprograms) для CUDA. Он позволяет получить доступ к вычислительным ресурсам графических процессоров NVIDIA. Библиотека является самодостаточной на уровне API, то есть, прямого взаимодействия с драйвером CUDA не происходит. CUBLAS прикрепляется к одному GPU и автоматически не распараллеливается между несколькими GPU.

Основные функции библиотеки CUBLAS: создание матриц и векторных объектов в пространстве памяти GPU, заполнение их данными, вызов последовательных функций CUBLAS, и загрузка результатов из области памяти GPU обратно к хосту. Чтобы достичь этого, CUBLAS предоставляет вспомогательные функции для создания и уничтожения объектов в памяти GPU, и для записи данных и извлечения информации из этих объектов.

Для максимальной совместимости с существующими средами Fortran, CUBLAS использует хранения в столбцах и индексирование с 1. Так как C и C++ используют построчное хранение, приложения не могут использовать родные семантики массивов для двумерных массивов. Вместо этого, макросы или встроенные функции должны быть определены для того чтобы использовать матрицы при помощи одномерных массивов. Для Fortran’а код портирован на C механическим способом, при котором сохраняется индексирование с 1. В этом случае индекс массива из матричного элемента в строке i и в столбце j могут быть вычислены с помощью следующего макроса:

#define IDX2F(i,j,ld) ((((j)-1)*(ld))+((i)-1))

Здесь ld — это размерности матрицы, в случае хранения в столбцах, является количеством строк. Для кода изначально написанного на С и С++, можно было бы использовать индексирование с 0, в этом случае макрос выглядит так:

#define IDX2C(i,j,ld) (((j)*(ld))+(i))

Из-за того что основные функции CUBLAS (в отличие от вспомогательных функций), не возвращают статус ошибки напрямую (из соображений совместимости с существующими библиотеками BLAS), CUBLAS предоставляет отдельную функцию, чтобы помочь в отладке, которая возвращает последнюю записанную ошибку.

Пример создания матрицы размерности 5 на 6:

#include <stdio.h> 
#include <stdlib.h> 
#include <math.h> 
#include "CUBLAS.h" 
 
#define IDX2F(i,j,ld) ((((j)-1)*(ld))+((i)-1)) 
 
void modify (float *m, int ldm, int n, int p, int q, float alpha, 
             float beta) 
{ 
    CUBLASSscal (n-p+1, alpha, &m[IDX2F(p,q,ldm)], ldm); 
    CUBLASSscal (ldm-p+1, beta, &m[IDX2F(p,q,ldm)], 1); 
} 
#define M 6 
#define N 5 
int main (void) 
{ 
    int i, j; 
    CUBLASStatus stat; 
    float* devPtrA; 
    float* a = 0; 
    a = (float *)malloc (M * N * sizeof (*a)); 
    if (!a) { 
        printf ("host memory allocation failed"); 
        return EXIT_FAILURE; 
    } 
    for (j = 1; j <= N; j++) { 
        for (i = 1; i <= M; i++) { 
            a[IDX2F(i,j,M)] = (i-1) * M + j; 
        } 
    } 
    CUBLASInit(); 
    stat = CUBLASAlloc (M*N, sizeof(*a), (void**)&devPtrA); 
    if (stat != CUBLAS_STATUS_SUCCESS) { 
        printf ("device memory allocation failed"); 
        return EXIT_FAILURE; 
    } 
    CUBLASSetMatrix (M, N, sizeof(*a), a, M, devPtrA, M); 
    modify (devPtrA, M, N, 2, 3, 16.0f, 12.0f); 
    CUBLASGetMatrix (M, N, sizeof(*a), devPtrA, M, a, M); 
    CUBLASFree (devPtrA); 
    CUBLASShutdown(); 
    for (j = 1; j <= N; j++) { 
        for (i = 1; i <= M; i++) { 
            printf ("%7.0f", a[IDX2F(i,j,M)]); 
        } 
        printf ("\n"); 
    } 
    return EXIT_SUCCESS; 
}