2010-07-20 90 views
4

我一直在這裏搞亂了一段時間,但似乎無法做到正確。我試圖複製包含數組到CUDA設備內存中的對象(和回來,但我會船到橋頭時,我來給它):結構中的指針傳遞給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就好了。但是,數據[idx] .data尚未被複制。

我不能在copyToGPU使用d_items.data作爲由於主機代碼cudaMalloc/cudaMemCpy操作的目的地不能解除引用的裝置指針。

怎麼辦?

回答

3
  • 將所有 結構的設備數據分配爲單個陣列。
  • 將連續數據從主機複製到 GPU。
  • 調整GPU指針

例如:

float *d_data; 
cudaMalloc((void**)&d_data, N*100*sizeof(float)); 
for (...) { 
    h_items[i].data = i*100 + d_data; 
} 
2

你只提供複印件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); 

但是,我假設你有多種長度的數據。一種解決方法是將LENGTH設置爲最大長度(並浪費一些空間),然後按照上述相同的方式進行。這可能是最簡單的方法,然後您可以稍後進行優化。

如果您不能負擔丟失的內存和傳輸時間,那麼我將有三個陣列,一個與所有的數據,然後用一個偏移和一個帶長度,爲主機和設備都:

//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]]