CUDA cublas getrf и getri для инверсии матрицы вызывают ошибки nvprof с одномерной памятью

Я пытаюсь использовать функции 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 для массива указателей?


person cshea    schedule 21.07.2015    source источник
comment
Ваши массивы a и c должны быть массивами устройств, а не массивами хостов. Скопируйте их на устройство перед вызовом пакетной процедуры getri CUBLAS.   -  person talonmies    schedule 21.07.2015
comment
Спасибо за указатель. Я не понял, что исходный код был для вычислительных возможностей 3.5, а я работаю над устройствами 3.0 и 3.2. Мой вопрос: как я могу добиться * a = a_i, как в исходном коде? a_i — указатель устройства на линейное пространство памяти.   -  person cshea    schedule 21.07.2015
comment
Полностью проработанный пример того, как использовать эти функции cubas для инверсии матриц в обычном использовании хост-кода, приведен здесь. Он делает инверсию матрицы 17x17 для обсуждения исторической проблемы, но это не влияет на настройку или последовательность вызовов API. Я склонен отметить этот вопрос как дубликат того. Вы можете разобраться в методе с этим примером?   -  person Robert Crovella    schedule 25.07.2015
comment
Да, это сработало. Что я действительно упустил, так это распределение устройств для p и info.   -  person cshea    schedule 26.07.2015