2014-03-03 66 views
2

我想知道當我分配一個結構然後分配(?)和複製一個相同結構的指針元素在設備上(內存明智)會發生什麼。cudaMalloc的結構和相同結構的元素

我需要的元素*一個再次cudaMalloc

示例代碼:

typedef struct { 
    int *a; 
    ... 
} StructA; 

int main() 
{ 
    int row, col, numS = 10; // defined at runtime 

    StructA *d_A = (StructA*)malloc(numS * sizeof(StructA)); 
    int *h_A = d_a->a; 

    cudaMalloc((void**)&(d_A), numS * sizeof(StructA)); 

    cudaMalloc(&(d_A->a), row*col*sizeof(int)); // no (void**) needed? 
    cudaMemcpy(d_A->a, h_A, row*col*sizeof(int), cudaMemcpyHostToDevice); 

    kernel<<<grid, block>>>(d_A); // Passing pointer to StructA in device 
    ... 
} 

內核定義:

__global__ kernel(StructA *d_A) 
{ 
    d_A->a = ...; 
    ... 
} 

這個問題的另一個this question延伸和相關this question

回答

6

我建議你花一些精力來編譯和運行你的代碼,並進行適當的cuda錯誤檢查。學習解釋編譯器輸出和運行時輸出將使您成爲更好,更智能,更高效的編碼器。我還建議查看我以前在here指出的那篇文章。它處理這個確切的主題,幷包括鏈接的工作示例。這個問題是一個重複的問題。

有各種錯誤:

StructA *d_A = (StructA*)malloc(numS * sizeof(StructA)); 

上面的代碼行創建在宿主存儲器大小StructA的結構的分配,並且將指針d_A指向該分配的開始。目前沒有錯。

cudaMalloc((void**)&(d_A), numS * sizeof(StructA)); 

上面的代碼行中設備創建的分配存儲器的StructA大小,並且將指針d_A指向該分配的開始。這有效地消除了以前的指針和分配。 (之前的主機分配仍然存在,但你無法訪問它,它基本上已經丟失。)當然,這不是你的意圖。

int *h_A = d_a->a; 

現在d_A(我假設你的意思d_A,不d_a)已經被指定爲設備內存指針,->操作將取消引用該指針定位元素a。這是主機代碼中的非法,並將引發錯誤(seg故障)。

cudaMalloc(&(d_A->a), row*col*sizeof(int)); 

這行代碼有類似的問題。我們不能cudaMalloc住在設備內存中的指針。 cudaMalloc創建生活在主機內存中的指針,但引用設備內存中的位置。此操作&(d_A->a)正在取消引用主機代碼中非法的設備指針。

正確的代碼會是這樣的:

$ cat t363.cu 
#include <stdio.h> 

typedef struct { 
    int *a; 
    int foo; 
} StructA; 

__global__ void kernel(StructA *data){ 

    printf("The value is %d\n", *(data->a + 2)); 
} 

int main() 
{ 
    int numS = 1; // defined at runtime 

    //allocate host memory for the structure storage 
    StructA *h_A = (StructA*)malloc(numS * sizeof(StructA)); 
    //allocate host memory for the storage pointed to by the embedded pointer 
    h_A->a = (int *)malloc(10*sizeof(int)); 
    // initialize data pointed to by the embedded pointer 
    for (int i = 0; i <10; i++) *(h_A->a+i) = i; 
    StructA *d_A; // pointer for device structure storage 
    //allocate device memory for the structure storage 
    cudaMalloc((void**)&(d_A), numS * sizeof(StructA)); 
    // create a pointer for cudaMalloc to use for embedded pointer device storage 
    int *temp; 
    //allocate device storage for the embedded pointer storage 
    cudaMalloc((void **)&temp, 10*sizeof(int)); 
    //copy this newly created *pointer* to it's proper location in the device copy of the structure 
    cudaMemcpy(&(d_A->a), &temp, sizeof(int *), cudaMemcpyHostToDevice); 
    //copy the data pointed to by the embedded pointer from the host to the device 
    cudaMemcpy(temp, h_A->a, 10*sizeof(int), cudaMemcpyHostToDevice); 

    kernel<<<1, 1>>>(d_A); // Passing pointer to StructA in device 
    cudaDeviceSynchronize(); 
} 
$ nvcc -arch=sm_20 -o t363 t363.cu 
$ cuda-memcheck ./t363 
========= CUDA-MEMCHECK 
The value is 2 
========= ERROR SUMMARY: 0 errors 
$ 

你會注意到,我還沒有制定出來,你所面對的是StructA(即numS> 1)的陣列的情況下,將需要一個循環。我會留給你看看我在這裏和我的previous linked answer中提出的邏輯,看看你是否可以計算出這個循環的細節。此外,爲了簡潔起見,我省去了通常的cuda error checking,但請在您的代碼中使用它。最後,如果你還沒有得出結論,這個過程(有時稱爲「深層複製操作」)在普通CUDA中有點繁瑣。沿着這些方向的先前建議是「扁平化」這種結構(以便它們不會控制指針),但是您也可以探索cudaMallocManaged,即Unified Memory in CUDA 6

+0

謝謝!這是關於'cudaMalloc'的最終解釋。我非常感謝你提供答案的時間。 'malloc'與下一個'cudaMalloc'所造成的分配是我以前沒有想到或知道的。 – mrei

+0

我正在玩你的示例代碼。由於我處於計算能力1.3環境,並且無法從設備打印,因此我試圖將修改的(例如'data-> a [2] = 5;')結構進行復制。但是,我無法複製回來(我認爲它會是:'cudaMemcpy(h_A,d_A,10 * sizeof(StructA),cudaMemcpyDeviceToHost);') – mrei

+0

這可能會複製結構,但它會不要複製由嵌入式指針指向的數據。如果您查看將該數據複製到設備的代碼行,您應該能夠將其反轉爲從設備中檢索該數據。如果你想取得進展,你需要對C結構,指針和動態分配有一個合理的理解。複製指針(這是結構中的內容)不會*複製指針指向的數據。 –