Передача данных с CPU на GPU без явной передачи их в качестве параметра

#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:

Вы можете использовать несколько подходов. Это зависит от того, как вы собираетесь использовать эти данные.

  1. Если ваш доступ к шаблону постоянный, и потоки внутри блока читают одно и то же местоположение, используйте __constant__ memory для трансляции запросов на чтение.
  2. Если ваш доступ к шаблону связан с соседями данной позиции или с произвольным доступом (не объединенным), тогда я рекомендую использовать текстурную память
  3. Если вам нужны данные для чтения / записи и вы знаете размер вашего массива, определите его как __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.