Этот пример решает системы линейного 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, 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 является верхней треугольной матрицей.
Для функций как 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) cudaPath = getenv('CUDA_PATH'); libPath = 'lib\x64'; buildInfo.addIncludePaths(fullfile(cudaPath,'include')); libName = 'cusolver'; libPath = fullfile(cudaPath,libPath); buildInfo.addSysLibs(libName, libPath); lapackLocation = 'C:\LAPACK\win64'; % specify path to LAPACK libraries includePath = fullfile(lapackLocation,'include'); buildInfo.addIncludePaths(includePath); libPath = fullfile(lapackLocation,'lib'); libName = 'mllapack'; [~,linkLibExt] = buildctx.getStdLibInfo(); buildInfo.addLinkObjects([libName linkLibExt], libPath, ... '', true, true); buildInfo.addDefines('HAVE_LAPACK_CONFIG_H'); buildInfo.addDefines('LAPACK_COMPLEX_STRUCTURE'); end end end