2013-12-17 22 views
0

我想通過ctypes使用python來控制cuda。在這裏,爲了說明我的問題,我使用python將指針傳遞給分配cuda內存的c函數,將numpy數組複製到cuda mempory,並將cuda內存複製回新的numpy數組。但它似乎沒有工作,儘管我的基本ctypes設置工作。我認爲問題是從cudaMalloc函數返回到python。在cuda上使用python句柄與ctypes分配內存

這裏的Python代碼

pycu_alloc = dll.alloc_gpu_mem 
    pycu_alloc.argtypes = [c_size_t] 
    pycu_alloc.restypes = [c_void_p] 

    host2gpu = dll.host2gpu 
    host2gpu.argtypes = [c_void_p, c_void_p, c_size_t] 

    gpu2host = dll.gpu2host 
    gpu2host.argtypes = [c_void_p, c_void_p, c_size_t] 

    a = np.random.randn(1024).astype('float32') 
    c = np.zeros(1024).astype('float32') 

    c_a = c_void_p(a.ctypes.data) 
    c_c = c_void_p(c.ctypes.data) 

    da = pycu_alloc(1024) 
    c_da = c_void_p(da) 

    host2gpu(c_a, c_da, 1024) 
    gpu2host(c_c, c_da, 1024) 

    print a 
    print c 

和C:

extern "C" { 
float * alloc_gpu_mem(size_t N) 
{ 
    float *d; 
    int size = N *sizeof(float); 
    int err; 

    err = cudaMalloc(&d, size); 

    printf("cuda malloc: %d\n", err); 
    return d; 
}} 

extern "C" { 
void host2gpu(float * a, void * da, size_t N) 
{ 
    int size = N * sizeof(float); 
    int err; 
    err = cudaMemcpy(da, a, size, cudaMemcpyHostToDevice); 
    printf("load mem: %d\n", err); 
    }} 

    extern "C"{ 
void gpu2host(float *c, void *d_c, size_t N) 
{ 
    int err; 
    int size = N*sizeof(float); 
    err = cudaMemcpy(c, d_c, size, cudaMemcpyDeviceToHost); 
    printf("cpy mem back %d\n", err); 
}} 

代碼應該隨機向量a複製到CUDA內存,然後複製CUDA內存回空載體c 。當我打印c時,認爲它只是0 s。

我已經與float*void*不同的可能性摔跤,特別是在alloc_gpu_mem的作品。但我不知道該怎麼做。

對於err返回值,該cudaMalloc回報0但兩者cudaMemcpy回報11

什麼蟒蛇做錯誤的指針?幫幫我?

+0

這並不直接回答你的問題,但是......您是否嘗試過[AndreasKlöckner](http://mathema.tician.de/software/pycuda/)的現有Python CUDA綁定(我認爲這與Nvidia從其網站鏈接的是相同的,但是我沒有檢查)? – abarnert

+0

不,我正在看那個,我可能應該使用它們,但我想潛入並控制自己的cuda,以確保我知道發生了什麼。那麼我就抓住了自己的蟒蛇手柄,因爲它對我來說真的很棒。可惜。 – Ethan

回答

4

的問題是在這裏:

pycu_alloc.restypes = [c_void_p] 

這並不做任何事情。你想要的是:

pycu_alloc.restype = c_void_p 

看到​​文檔Return types

沒有這個,​​假定你的函數返回一個C int。在32位平臺上,您可能會忽略它,因爲您最終構建的c_void_p的值爲int ...但在64位平臺上,該指針最終會丟失高32位。

所以,當你將它傳遞給CUDA時,它會識別出指針不在它所知道的任何範圍內,並且返回一個cudaErrorInvalidValue(11)。

另外,如果你得到的一切權利,這條線應該是不必要的:

c_da = c_void_p(da) 

你調用其argtypes指定c_void_p的函數,因此你可以通過它的int您從c_void_p了 - 返回函數就好了。


你可以看到普通的舊mallocfree相同的行爲,但你可能會在free,而不是一個友好的錯誤得到段錯誤:

malloc = libc.malloc 
malloc.argtypes = [c_size_t] 
malloc.restype = c_void_p # comment this line to crash on most 64-bit platforms 

free = libc.free 
free.argtypes = [c_void_p] 
free.restype = None 

a = malloc(1024) 
free(a) # commenting this line and uncommenting the next two has no effect 
#c_a = c_void_p(a) 
#free(ca) 
+0

WOOOOHOOOOOOOO !!!!非常感謝你,親愛的朋友。快樂,祝你好運 – Ethan

+1

@Ethan:請記住,對於具有數據描述符的類型,仍然會給實例賦予'__dict__'。 ctypes數據類型允許這樣做,因爲它們被設計爲被子類化以支持附加的狀態和接口。不幸的是,很容易錯誤地創建一個像「restypes」這樣的新屬性。如果您試圖將'[c_void_p]'分配給正確的'restype'屬性,您至少會得到一個'TypeError'。 REPL,'dir'和'help'是你的朋友。 – eryksun