Пример cuSOLVER

Этот пример решает системы линейного equations Ax = B для x при помощи cuSOLVER библиотеки. Матрицы A и B должен иметь одинаковое число строк. Если A скаляр, затем A\B эквивалентно A.\B. Если A квадратная n на n матрица и B матрица с n строками, затем x = A\B решение уравнения A*x = B, если это существует. MATLAB® реализация backslash :

function [x] = backslash(A,b)
if (isscalar(A))
    x = coder.nullcopy(zeros(size(b)));
else
    x = coder.nullcopy(zeros(size(A,2),size(b,2)));
end

x = A\b;

end

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

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

function [x] = backslash(A,b) %#codegen

if (isscalar(A))
    x = coder.nullcopy(zeros(size(b)));
else
    x = coder.nullcopy(zeros(size(A,2),size(b,2)));
end

coder.gpu.kernelfun()
x = A\b;

end

Примечание

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

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

Когда вы генерируете код CUDA, GPU Coder создает вызовы функции инициализировать cuSOLVER библиотеку, выполнить mldivide операции и аппаратные ресурсы релиза, которые использует cuSOLVER библиотека. Отрывок сгенерированного кода CUDA:

  cusolverEnsureInitialization();

  /*    Copyright 2017 The MathWorks, Inc. */
  cudaMemcpy(b_gpu_A, A, 1152UL, cudaMemcpyHostToDevice);  
  blackslash_kernel1<<<dim3(1U, 1U, 1U), dim3(160U, 1U, 1U)>>>(b_gpu_A,gpu_A);
  cudaMemcpy(b_A, gpu_A, 1152UL, cudaMemcpyDeviceToHost);
  cusolverDnDgetrf_bufferSize(cusolverGlobalHandle, 12, 12, &gpu_A[0], 12,
    &cusolverWorkspaceReq);
  cusolverWorkspaceTypeSize = 8;
  cusolverInitWorkspace();
  cudaMemcpy(gpu_A, b_A, 1152UL, cudaMemcpyHostToDevice);
  cusolverDnDgetrf(cusolverGlobalHandle, 12, 12, &gpu_A[0], 12, (real_T *)
                   cusolverWorkspaceBuff, &gpu_ipiv_t[0], gpu_info_t);
  A_dirtyOnGpu = true;
  cudaMemcpy(&info_t, gpu_info_t, 4UL, cudaMemcpyDeviceToHost);

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

static void cusolverEnsureInitialization(void)
{
  if (cusolverGlobalHandle == NULL) {
    cusolverDnCreate(&cuSolverGlobalHandle);
  }
}

backslash_kernel1 обнулите заполняет матричный A. Это ядро запускается с одним блоком 512 потоков.

static __global__ __launch_bounds__(160, 1) void backslash_kernel1(const real_T *
  A, real_T *b_A)
{
  int32_T threadId;
  ;
  ;
  threadId = (int32_T)(((gridDim.x * gridDim.y * blockIdx.z + gridDim.x *
    blockIdx.y) + blockIdx.x) * (blockDim.x * blockDim.y * blockDim.z) +
                       (int32_T)((threadIdx.z * blockDim.x * blockDim.y +
    threadIdx.y * blockDim.x) + threadIdx.x));
  if (!(threadId >= 144)) {
    /*    Copyright 2017 The MathWorks, Inc. */
    b_A[threadId] = A[threadId];
  }
}

Вызовы cudaMemcpy передайте матричный A с хоста на устройство. Функциональный cusolverDnDgetrf вычисляет LU-факторизацию матрицы m×n:

P*A = L*U

где A является матрицей m×n, P является матрицей перестановок, L является нижней треугольной матрицей с модульной диагональю, и U является верхней треугольной матрицей.

cuSOLVER Автономный Код

Для функций как qr то единственное имеет частичную поддержку в cuSOLVER, GPU Coder пользуется библиотекой LAPACK в случае необходимости. Для MEX-функций генератор кода пользуется библиотекой LAPACK, которая включена с MATLAB. Для автономного кода генератор кода пользуется библиотекой LAPACK, которую вы задаете. Задавать библиотеку LAPACK:

  • В командной строке задайте свой собственный coder.LAPACKCallback класс, содержащий информацию о библиотеке LAPACK и присвоение это к CustomLAPACKCallback свойство объекта настройки кода.

  • В приложении GPU Coder, коллбэке библиотеки Custom LAPACK набора к вашей библиотеке LAPACK.

Например, чтобы сгенерировать независимый исполняемый файл, можно использовать следующий скрипт генерации кода. Здесь myLAPACK имя пользовательского coder.LAPACKCallback класс, содержащий информацию о библиотеке LAPACK.

cfg = coder.gpuConfig('exe');
cfg.CustomLAPACKCallback = 'myLAPACK';
cfg.GenerateExampleMain = 'GenerateCodeAndCompile';

classdef myLAPACK < coder.LAPACKCallback
    methods (Static)
        function hn = getHeaderFilename()
            hn = 'lapacke.h';
        end
        function updateBuildInfo(buildInfo, buildctx)
            [~,linkLibExt] = buildctx.getStdLibInfo();
            cudaPath = getenv('CUDA_PATH'); 
            libPath = 'lib\x64';            
            
            buildInfo.addIncludePaths(fullfile(cudaPath,'include'));
            libName = 'cusolver';
            libPath = fullfile(cudaPath,libPath);
            buildInfo.addLinkObjects([libName linkLibExt], libPath, ...
                '', true, true);
            
            lapackLocation = 'C:\LAPACK\win64'; % specify path to LAPACK libraries 
            
            includePath = fullfile(lapackLocation,'include');
            buildInfo.addIncludePaths(includePath);
            libPath = fullfile(lapackLocation,'lib');
            libName = 'mllapack';
            
            buildInfo.addLinkObjects([libName linkLibExt], libPath, ...
                '', true, true);
            buildInfo.addDefines('HAVE_LAPACK_CONFIG_H');
            buildInfo.addDefines('LAPACK_COMPLEX_STRUCTURE');
        end
    end
end
Для получения дополнительной информации смотрите, Ускоряют Линейную алгебру в Сгенерированном Автономном Коде при помощи Вызовов LAPACK.