#c #cuda #gpgpu
#c #cuda #gpgpu
Вопрос:
Возможно ли передать данные с CPU на GPU без явной передачи их в качестве параметра?
Я не хочу передавать их в качестве параметра в первую очередь по причинам синтаксического сахара — у меня есть около 20 постоянных параметров, которые мне нужно передать, а также потому, что я последовательно вызываю два ядра с (почти) одинаковыми параметрами.
Я хочу что-то вроде
__constant__ int* blah;
__global__ myKernel(...){
... i want to use blah inside ...
}
int main(){
...
cudaMalloc(...allocate blah...)
cudaMemcpy(copy my array from CPU to blah)
}
Комментарии:
1. Почему бы вместо этого не упаковать ваши параметры в структуру? Следует избегать отмывания параметров через глобальные переменные.
Ответ №1:
cudaMemcpyToSymbol, похоже, является функцией, которую вы ищете. Это работает аналогично cudaMemcpy, но с дополнительным аргументом ‘offset’, который, похоже, упростит копирование в 2D-массивах.
(Я не решаюсь предоставить код, поскольку я не могу его протестировать — но смотрите Этот поток и этот пост для справки.)
Ответ №2:
используйте __device__
для применения глобальных переменных. Это похоже на способ использования __constant__
Ответ №3:
Вы можете использовать несколько подходов. Это зависит от того, как вы собираетесь использовать эти данные.
- Если ваш доступ к шаблону постоянный, и потоки внутри блока читают одно и то же местоположение, используйте __constant__ memory для трансляции запросов на чтение.
- Если ваш доступ к шаблону связан с соседями данной позиции или с произвольным доступом (не объединенным), тогда я рекомендую использовать текстурную память
- Если вам нужны данные для чтения / записи и вы знаете размер вашего массива, определите его как __device__ blah[size] в вашем ядре.
В примере:
__constant__ int c_blah[65536]; // constant memory
__device__ int g_blah[1048576]; // global memory
__global__ myKernel() {
// ... i want to use blah inside ...
int idx = threadIdx.x blockIdx.x * blockDim.x;
// get data from constant memory
int c = c_blah[idx];
// get data from global memory
int g = g_blah[idx];
// get data from texture memory
int t = tex1Dfetch(ref, idx);
// operate
g_blah[idx] = c g t;
}
int main() {
// declare array in host
int c_h_blah[65536]; // and initialize it as you want
// copy from host to constant memory
cudaMemcpyToSymbol(c_blah, c_h_blah, 65536*sizeof(int), 0, cudaMemcpyHostToDevice);
// declare other array in host
int g_h_blah[1048576]; // and initialize it as you want
// declare one more array in host
int t_h_blah[1048576]; // and initialize it as you want
// declare a texture reference
texture<int, 1, cudaReadModeElementType> tref;
// bind the texture to the array
cudaBindTexture(0,tref,t_h_blah, 1048576*sizeof(int));
// call your kernel
mykernel<<<dimGrid, dimBlock>>>();
// copy result from GPU to CPU memory
cudaMemcpy(g_h_blah, g_blah, 1048576*sizeof(int), cudaMemcpyDeviceToHost);
}
Вы можете использовать три массива в ядре, не передавая ядру никаких параметров. Обратите внимание, что это только пример использования, а не оптимизированное использование иерархии памяти, т. Е.: Использовать постоянную память таким образом не рекомендуется.
Надеюсь, это поможет.
Комментарии:
1. Подход 3 не будет работать.
__device__
объявления внутри тела функции в CUDA недопустимы.2. @talonmies Но мы можем объявить _ device_ в глобальной области видимости файла, не так ли?
3. да, это сработает, хотя и будет генерировать предупреждения компилятора для целей compute 1.x .
4. Спасибо, но возможно ли это сделать, если я заранее не знаю размер c_blah? Как и в — я знаю заранее перед запуском ядра, но я не знаю этого во время компиляции. Выполнение постоянной переменной с плавающей точкой * c_blah, за которым следуют cudaMalloc() и cudaMemcpyToSymbol, похоже, работает не слишком хорошо.
5. @cheshire Вы не можете динамически выделять память устройства. Вам нужно определить указатель вашего устройства int * c_blah и выделить для него память в CPU.