Я пытаюсь использовать функции cuBlas cublasSgetrf и cublasSgetri, чтобы найти инверсию квадратной матрицы. Эта часть кода является частью более крупной программы, в которой я пытаюсь свести к минимуму любые ненужные выделения памяти или копии. В рамках своих усилий я использовал nvprof для профилирования всего приложения и отдельных функций. Я обнаружил, что когда я начинал включать sgetrf или sgetri, NVPROF выдавал ошибку: ==7734== Предупреждение: в результате найдено 20 недопустимых записей. ==7734== Предупреждение. Это может произойти, если на устройстве закончилась память или если ядро устройства было остановлено из-за утверждения.
Я изолировал проблемный код и создал рабочее приложение ниже.
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <cuda_runtime_api.h>
#include <cublas_v2.h>
#include <math.h>
#define CUDA(call) do { \
cudaError_t err = call; \
if (err != cudaSuccess) \
{ \
printf("CUDA ERROR at line : %d, file : %s, %s\n", __LINE__, __FILE__, cudaGetErrorString(err)); \
exit(-1); \
} \
} while(0);
#define cublascall(call) \
do \
{ \
cublasStatus_t status = (call); \
if(CUBLAS_STATUS_SUCCESS != status) { \
fprintf(stderr,"CUBLAS Error:\nFile = %s\nLine = %d\nCode = %d\n", __FILE__, __LINE__, status); \
cudaDeviceReset(); \
exit(EXIT_FAILURE); \
} \
} \
while(0)
void invertMatrixGPU(float* a_i, float* c_o, int n, int ldda, cublasHandle_t hdl)
{
int *p = (int *)malloc(n*sizeof(int));
int *info = (int *)malloc(sizeof(int));
int batch;
int INFOh = 0;
batch = 1;
float **a = NULL;
cudaMalloc(a,sizeof(float*));
*a = a_i;
float **c = NULL;
cudaMalloc(c,sizeof(float*));
*c = c_o;
// See
//http://docs.nvidia.com/cuda/pdf/CUDA_Dynamic_Parallelism_Programming_Guide.pdf
//http://stackoverflow.com/questions/27094612/cublas-matrix-inversion-from-device
cublascall(cublasSgetrfBatched(hdl, n, a, ldda, p, info, batch));
cudaMemcpy(&INFOh,info,sizeof(int),cudaMemcpyDeviceToHost);
if(INFOh != 0)
{
fprintf(stderr, "Inversion Failed: Matrix is singular\n");
cudaDeviceReset();
exit(EXIT_FAILURE);
}
cublascall(cublasSgetriBatched(hdl, n, (const float **)a, ldda, p, c, ldda, info, batch));
cudaMemcpy(&INFOh,info,sizeof(int),cudaMemcpyDeviceToHost);
if(INFOh != 0)
{
fprintf(stderr, "Inversion Failed: Matrix is singular\n");
cudaDeviceReset();
exit(EXIT_FAILURE);
}
}
int main() {
// Initialize GPU for CUDA
CUDA(cudaSetDevice(0));
cublasHandle_t handle;
cublasCreate(&handle);
float *matrix = (float*)malloc(sizeof(float)*4*4);
for (int i=0;i<16;i++)
{
matrix[i] = i;
}
float *matrix_d = NULL;
CUDA(cudaMalloc(&matrix_d,sizeof(float)*4*4));
CUDA(cudaMemcpy(matrix_d,matrix,sizeof(float)*4*4,cudaMemcpyHostToDevice));
float *matrix_di = NULL;
CUDA(cudaMalloc(&matrix_di,sizeof(float)*4*4));
for (int i = 0;i<10;i++){
invertMatrixGPU(matrix_d, matrix_di,4,4, handle);
}
free(matrix);
cudaFree(matrix_d);
cudaFree(matrix_di);
cublasDestroy(handle);
}
Я считаю, что проблема заключается в преобразовании одномерного распределения памяти matrix_d в массив указателей, которые передаются в cublasSgetrf и cublasSgetri. Если это проблема, может ли кто-нибудь порекомендовать метод, который сводит к минимуму выделение данных и копирование, но при этом удовлетворяет требованию cublasSgetrf/i для массива указателей?
a
иc
должны быть массивами устройств, а не массивами хостов. Скопируйте их на устройство перед вызовом пакетной процедуры getri CUBLAS. - person talonmies   schedule 21.07.2015