Указатели в структурах переданы в CUDA - PullRequest
4 голосов
/ 20 июля 2010

Я уже давно возился с этим, но, похоже, не могу понять это правильно.Я пытаюсь скопировать объекты, которые содержат массивы, в память устройства CUDA (и обратно, но я перейду этот мост, когда приду к нему):

struct MyData {
  float *data;
  int dataLen;
}

void copyToGPU() {
  // Create dummy objects to copy
  int N = 10;
  MyData *h_items = new MyData[N];
  for (int i=0; i<N; i++) {
    h_items[i].dataLen = 100;
    h_items[i].data = new float[100];
  }

  // Copy objects to GPU
  MyData *d_items;
  int memSize = N * sizeof(MyData);
  cudaMalloc((void**)&d_items, memSize);
  cudaMemCpy(d_items, h_items, memSize, cudaMemcpyHostToDevice);

  // Run the kernel
  MyFunc<<<100,100>>>(d_items);
}

__global__
static void MyFunc(MyData *data) {
  int idx = blockIdx.x * blockDim.x + threadIdx.x;
  for (int i=0; i<data[idx].dataLen; i++) {
    // Do something with data[idx].data[i]
  }
}

Когда я вызываю MyFunc (d_items),Я могу получить доступ к данным [idx] .dataLen просто отлично.Однако data [idx] .data еще не скопированы.

Я не могу использовать d_items.data в copyToGPU в качестве места назначения для операций cudaMalloc / cudaMemCpy, поскольку код хоста не может разыменовать указатель устройства.

Что делать?

Ответы [ 2 ]

3 голосов
/ 21 июля 2010
  • выделить данные устройства для всех структур в виде единого массива.
  • Копировать непрерывные данные с хоста на графический процессор.
  • настроить указатели графического процессора

пример:

float *d_data;
cudaMalloc((void**)&d_data, N*100*sizeof(float));
for (...) {
    h_items[i].data = i*100 + d_data;
}
2 голосов
/ 29 марта 2011

Код, который вы предоставляете, копирует только структуры MyData: адрес хоста и целое число.Чтобы быть слишком ясным, вы копируете указатель, а не данные - вы должны явно копировать данные.

Если данные всегда одинаковы LENGTH, то вы, вероятно, просто хотите создать один большой массив:

float *d_data;
memSize = N * LENGTH * sizeof(float);
cudaMalloc((void**) &d_data, memSize);

//and a single copy
cudaMemcpy(d_data, h_data, memSize, cudaMemcpyHostToDevice);

Если он должен быть в структуре с другими данными, то:

struct MyData {
  float data[LENGTH];
  int other_data;
}

MyData *d_items;
memSize = N * sizeof(MyData);
cudaMalloc((void**) &d_items, memSize);

//and again a single copy
cudaMemcpy(d_data, h_data, memSize, cudaMemcpyHostToDevice);

Но я предполагаю, что у вас есть данные различной длины.Одно из решений состоит в том, чтобы установить ДЛИНУ на максимальную длину (и просто потратить некоторое пространство), а затем сделать это так же, как описано выше.Это может быть самый простой способ начать, а потом оптимизировать позже.

Если вы не можете позволить себе потерянную память и время передачи, тогда у меня будет три массива, один со всеми данными, а затем одинсо смещениями и длиной, для хоста и устройства:

//host memory
float *h_data;
int h_offsets[N], h_lengths[N]; //or allocate these dynamically if necessary
int totalLength;

//device memory
float *d_data;
int *d_offsets, *d_lengths;

/* calculate totalLength, allocate h_data, and fill the three arrays */

//allocate device memory
cudaMalloc((void**) &d_data, totalLength * sizeof(float));
cudaMalloc((void**) &d_ffsets, N * sizeof(int));
cudaMalloc((void**) &d_lengths, N * sizeof(int));

//and now three copies
cudaMemcpy(d_data, h_data, totalLength * sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(d_offsets, h_offsets, N * sizeof(int); cudaMemcpyHostToDevice);
cudaMemcpy(d_lengths, h_lengths, N * sizeof(int); cudaMemcpyHostToDevice);

Теперь в потоке i вы можете найти данные, которые начинаются с d_data[d_offsets[i]] и имеют длину d_data[d_lengths[i]]* 1020.*

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...