Как использовать 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 ответ
- Выделите память для
B
сcudaMalloc()
- Скопируйте его с хоста на устройство с
cudaMemcpy()
- Передать указатель устройства в список аргументов ядра
Наконец вы используете его из ядра с аргументом, который вы передали! Пример:
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 байтов).