2012-09-03 64 views
3

CUDA編程指南指出:「通過malloc()分配的內存可以使用運行時進行復制(即通過調用設備內存中的任何複製內存功能)」,但不知何故我無法重現此功能。代碼:複製到由malloc()分配的全局內存?

#include <cstdio> 
__device__ int* p; 

__global__ void allocate_p() { 
    p = (int*) malloc(10); 
    printf("p = %p (seen by GPU)\n", p); 
} 

int main() { 
    cudaError_t err; 
    int* localp = (int*) malloc(10); 

    allocate_p<<<1,1>>>(); 
    cudaDeviceSynchronize(); 

    //Getting pointer to device-allocated memory 
    int* tmpp = NULL; 
    cudaMemcpyFromSymbol(&tmpp, p, 4); 
    printf("p = %p (seen by CPU)\n", tmpp); 

    //cudaMalloc((void**)&tmpp, 40); 
    err = cudaMemcpy(tmpp, localp, 40, cudaMemcpyHostToDevice); 
    cudaDeviceSynchronize(); 
    printf(" err:%i %s", (int)err, cudaGetErrorString(err)); 

    delete localp; 
    return 0; 
} 

崩潰,輸出:

p = 0x601f920 (seen by GPU) 
p = 0x601f920 (seen by CPU) 
err:11 invalid argument 

我推測,在主機上看到設備的相應地址,但不知何故不喜歡它malloc()到來。

如果我分配早些時候cudaMalloc((void**)&np, 40);然後傳遞指針np作爲參數內核allocate_p,在那裏將被分配到p(代替malloc()),則代碼運行正常。

我在做什麼錯誤/我們如何在主機端函數中使用malloc()分配的設備內存?

+0

您引用的部分來自「B.17.2與主機內存API的互操作性」部分。 malloc()指的是主機malloc()而不是設備malloc()。考慮到引入設備malloc()的「B.17.1堆內存分配」部分,這是非常令人困惑的。 –

+0

@GregSmith:我不明白你是如何達到這種解釋的。該部分是關於設備動態內存分配(甚至有代碼示例顯示內核malloc調用),並且參考是在第3.2.2節中介紹的主機內存API函數,即。 cudaMemcpy。 *主機* malloc進入圖片的位置在哪裏?我不會說它是混淆編寫的,我會說這只是錯誤的(或者在運行時有一個巨大的錯誤作爲替代)。 – talonmies

+0

@部分是的,該部分在較舊的手冊中是錯誤的,並被複制到不同的位置。該聲明應從編程指南的下一個版本中刪除。 –

回答

3

據我所知,使用主機API函數複製運行時堆內存是不可能的。 CUDA 4.x當然不可能,CUDA 5.0版本的候選版本並沒有改變這一點。我可以提供的唯一解決方法是使用內核來「收集」最終結果,並將它們填充到設備傳輸緩衝區或零副本內存中,這些內存可以通過API或直接從主機訪問。您可以在this answeranother question中看到這種方法的示例,NVIDIA的Mark Harris確認這是CUDA運行時當前實現的限制。

+0

另一個解決方法是根本不使用'__device__ malloc()',而是先分配內存並將其放入內核中,對吧?特別是如果'__device__ malloc()'是恆定大小的,就像例子中那樣。另外,我認爲'__device__ malloc()'可能會導致同時進行調用的線程的隱式序列化(以便它們中的每一個都可以從堆中分配它自己的塊)。 –

+0

@RogerDahl:在大多數情況下,我會同意。在某些情況下,使用「setup」內核在內核malloc中構建堆中的數據結構,然後讓設備代碼完全在堆中的結構上工作,然後最終將最終結果複製回主機「下拉/收集」內核。深度遞歸數據結構基本上不可能僅使用主機API分配和初始化。 – talonmies

+0

謝謝;這讓我很生氣(根據指南的說法)。由於我在host('tmpp')上有設備地址,我嘗試將從cudaMalloc()獲得的其他指針移動到指向malloc()分配的設備內存。 (這很愚蠢,但我認爲CUDA可能有一些RTTI區分指針。)顯然,主機端分配器範圍 - 檢查內存操作與它明確分配的內容。另一方面,設備端分配器相當寬鬆,甚至不會報告未分配's'的'free(s)'。我正在用'-arch = sm_21'在CUDA 5.0上測試它。 –