Я пытаюсь сделать приложение в CUDA, которое использует глобальную память, определенную с устройство.
Эти переменные объявлены в файле .cuh.
В другом файле .cu мой основной, в котором я делаю cudaMallocs и cudaMemCpy.
Это часть моего кода:
cudaMalloc((void**)&varOne,*tam_varOne * sizeof(cuComplex));
cudaMemcpy(varOne,C_varOne,*tam_varOne * sizeof(cuComplex),cudaMemcpyHostToDevice);
varOne объявлен в файле .cuh следующим образом:
__device__ cuComplex *varOne;
Когда я запускаю свое ядро (я не передаю varOne в качестве параметра) и пытаюсь прочитать varOne с помощью отладчика, он говорит, что не может прочитать переменную. Указатель обращается к нему 000..0, так что очевидно, что это неправильно.
Итак, как мне объявить и скопировать глобальную память в CUDA?
Вы должны сначала определить указатели, которые будут содержать данные, которые будут скопированы в CUDA:
В приведенном выше примере мы, что скопировать массив original_cpu_array
к CUDA глобальной памяти.
int original_cpu_array[array_size];
int *array_cuda;
рассчитать размер, который будут занимать данные.
int size = array_size * sizeof(int);
Распределение памяти Cuda:
msg_erro[0] = cudaMalloc((void **)&array_cuda,size);
Копирование с CPU на GPU:
msg_erro[0] = cudaMemcpy(array_cuda, original_cpu_array,size,cudaMemcpyHostToDevice);
Выполнить ядро
Копирование из GPU в CPU:
msg_erro[0] = cudaMemcpy(original_cpu_array,array_cuda,size,cudaMemcpyDeviceToHost);
Свободная память:
cudaFree(array_cuda);
Для отладки я обычно сохраняю состояние функций в массиве (cudaError_t msg_erro [var];). Однако это не является строго необходимым, но сэкономит ваше время, если во время выделения или передачи памяти произойдет ошибка.
И если произошли ошибки, я печатаю, используя что-то вроде:
void printErros(cudaError_t *erros,int size, int flag)
{
for(int i = 0; i < size; i++)
if(erros[i] != 0)
{
if(flag == 0) printf("Alocacao de memoria");
if(flag == 1) printf("CPU -> GPU ");
if(flag == 2) printf("GPU -> CPU ");
printf("{%d} => %s\n",i ,cudaGetErrorString(erros[i]));
}
}
Флаг в первую очередь указывает на ту часть кода, в которой произошла ошибка. Например, после выделения памяти:
msg_erro[0] = cudaMalloc((void **)&array_cuda,size);
printErros(msg_erro,msg_erro_size, 0);
Я экспериментировал с некоторым примером и обнаружил, что нельзя напрямую использовать глобальную переменную в ядре, не переходя к ней. Даже если вы инициализируете в файле .cuh, вам нужно инициализировать в main ().
Причина:
cudaMalloc((void**)&varOne,sizeof(cuComplex))
для выделения памяти. Он может только распределять память на GPU. Декларация __device__ cuComplex *varOne;
работает так же, как объявление прототипа и переменной. Но память не выделяется до cudaMalloc((void**)&varOne,sizeof(cuComplex))
используется.*varOne
в main () в качестве указателя на хост изначально. После использования cudaMalloc()
, он узнает, что указатель — это Device Pointer.Последовательность шагов: (для моего проверенного кода)
int *Ad; //If you can allocate this in .cuh file, you dont need the shown code in main()
__global__ void Kernel(int *Ad){
....
}
int main(){
....
int size=100*sizeof(int);
cudaMalloc((void**)&Ad,size);
cudaMemcpy(Ad,A,size,cudaMemcpyHostToDevice);
....
}