Как использовать 3D-матрицы с CULA на GPU?

Поэтому в настоящий момент в версии CPU для некоторого кода у меня есть много вещей, которые выглядят следующим образом:

for(int i =0;i<N;i++){

    dgemm(A[i], B[i],C[i], Size[i][0], Size[i][1], Size[i][2], Size[i][3], 'N','T');

}

где A[i] будет двухмерной матрицей некоторого размера.

Я хотел бы иметь возможность делать это на GPU с использованием CULA (я не просто делаю умножения, поэтому мне нужны операции Linear ALgebra в CULA), например, так:

 for(int i =0;i<N;i++){
        status = culaDeviceDgemm('T', 'N', Size[i][0], Size[i][0], Size[i][0], alpha, GlobalMat_d[i], Size[i][0], NG_d[i], Size[i][0], beta, GG_d[i], Size[i][0]);
}

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

В Интернете я видел разные вещи об использовании 3D-матриц с CUDA, но они не очень подходят для того, чтобы потом вызывать функцию для функций CULA.

Во всяком случае.. Я действительно не знаю лучший способ сделать это, у кого-нибудь есть какие-нибудь идеи?

Хорошо, из примера в ответе ниже у меня есть это:

extern "C" void copyFNFVecs_(double **FNFVecs, int numpulsars, int numcoeff){


  cudaError_t err;
 err = cudaMalloc( (void ***)&GlobalFVecs_d, numpulsars*sizeof(double*) );
 checkCudaError(err);

    for(int i =0; i < numpulsars;i++){
         err = cudaMalloc( (void **) &(GlobalFVecs_d[i]), numcoeff*numcoeff*sizeof(double) );
         checkCudaError(err);    
       //  err = cudaMemcpy( GlobalFVecs_d[i], FNFVecs[i], sizeof(double)*numcoeff*numcoeff, cudaMemcpyHostToDevice );
        // checkCudaError(err); 
        }

}

где я объявил двойной **GlobalFVecs_d, чтобы быть глобальным.. но я получаю ошибку сегмента, когда он попадает в строку

 err = cudaMalloc( (void **) &(GlobalFVecs_d[i]), numcoeff*numcoeff*sizeof(double) );

все же, похоже, что именно в другом примере?

EDIT2:

Хорошо, я понял, что это не то же самое, поэтому у меня теперь есть код, который компилируется с:

double **GlobalFVecs_d;
double **GlobalFPVecs_d;

extern "C" void copyFNFVecs_(double **FNFVecs, int numpulsars, int numcoeff){


  cudaError_t err;
  GlobalFPVecs_d = (double **)malloc(numpulsars * sizeof(double*));
 err = cudaMalloc( (void ***)&GlobalFVecs_d, numpulsars*sizeof(double*) );
 checkCudaError(err);

    for(int i =0; i < numpulsars;i++){
         err = cudaMalloc( (void **) &(GlobalFPVecs_d[i]), numcoeff*numcoeff*sizeof(double) );
         checkCudaError(err);    
         err = cudaMemcpy( GlobalFPVecs_d[i], FNFVecs[i], sizeof(double)*numcoeff*numcoeff, cudaMemcpyHostToDevice );
         checkCudaError(err);   
        }

         err = cudaMemcpy( GlobalFVecs_d, GlobalFPVecs_d, sizeof(double*)*numpulsars, cudaMemcpyHostToDevice );
         checkCudaError(err);

}

но если я сейчас попытаюсь получить к нему доступ с помощью:

 dim3 dimBlock(BLOCK_SIZE, BLOCK_SIZE);
 dim3 dimGrid;//((G + dimBlock.x - 1) / dimBlock.x,(N + dimBlock.y - 1) / dimBlock.y);
 dimGrid.x=(numcoeff + dimBlock.x - 1)/dimBlock.x;
 dimGrid.y = (numcoeff + dimBlock.y - 1)/dimBlock.y;

 for(int i =0; i < numpulsars; i++){
    CopyPPFNF<<<dimGrid, dimBlock>>>(PPFMVec_d, GlobalFVecs_d[i], numpulsars, numcoeff, i);
 }

вместо этого здесь обнаруживаются ошибки, разве это не как получить данные?

1 ответ

Решение
  1. Выделите память для B с cudaMalloc()
  2. Скопируйте его с хоста на устройство с cudaMemcpy()
  3. Передать указатель устройства в список аргументов ядра

Наконец вы используете его из ядра с аргументом, который вы передали! Пример:

  1     //  Kernel definition, see also section 4.2.3 of Nvidia Cuda Programming Guide 
  2     __global__  void vecAdd(float* A, float* B, float* C) 
  3     { 
  4        // threadIdx.x is a built-in variable  provided by CUDA at runtime 
  5        int i = threadIdx.x; 
  6        A[i]=0; 
  7        B[i]=i; 
  8        C[i] = A[i] + B[i]; 
  9     } 
  10     
  11     #include  <stdio.h> 
  12     #define  SIZE 10 
  13     int  main() 
  14     { 
  15         int N=SIZE; 
  16         float A[SIZE], B[SIZE], C[SIZE]; 
  17         float *devPtrA; 
  18         float *devPtrB; 
  19         float *devPtrC; 
  20         int memsize= SIZE * sizeof(float); 
  21     
  22         **cudaMalloc((void**)&devPtrA, memsize);** 
  23         cudaMalloc((void**)&devPtrB, memsize); 
  24         cudaMalloc((void**)&devPtrC, memsize); 
  25         **cudaMemcpy(devPtrA, A, memsize,  cudaMemcpyHostToDevice);** 
  26         cudaMemcpy(devPtrB, B, memsize,  cudaMemcpyHostToDevice); 
  27         // __global__ functions are called:  Func<<< Dg, Db, Ns  >>>(parameter); 
  28         **vecAdd<<<1, N>>>(devPtrA,  devPtrB, devPtrC);** 
  29         cudaMemcpy(C, devPtrC, memsize,  cudaMemcpyDeviceToHost); 
  30     
  31         for (int i=0; i<SIZE; i++) 
  32          printf("C[%d]=%f\n",i,C[i]); 
  33     
  34          cudaFree(devPtrA); 
  35         cudaFree(devPtrA); 
  36         cudaFree(devPtrA); 
  37     } 

** области являются важной частью для вас. Пример взят здесь. Вы можете посмотреть на этот вопрос.

РЕДАКТИРОВАТЬ #1: Прежде всего, чтобы объявить функцию ядра, вам нужно поместить ключевое слово __global__ перед возвращаемым типом, например

__global__ void copyFNFVecs_(double **FNFVecs, int numpulsars, int numcoeff),

Более того, я бы использовал только один указатель на первый элемент матрицы, который у вас есть.

double *devPtr,

Выделите это с

cudaMalloc((void*)&devPtr, size)

а затем скопировать

cudaMemcpy(devPtr, hostPtr, size, hostToDevice),

Обратите внимание, что для расчета размера вашей структуры вам нужны размеры (скажем, X и Y) и размер базового типа элементов (скажем, double).

size_t size = X*Y*sizeof(double),

sizeof(double *) означает неверный размер указателя на double (на 32-битных машинах размер указателя составляет 4 байта, а размер double - 8 байтов).

Другие вопросы по тегам