2012-01-07 62 views
2

我不能設法訪問我的常量內存中的數據,我不知道爲什麼。這是我的代碼片段:如何在我的內核中訪問我的常量內存?

#define N 10 
__constant__ int constBuf_d[N]; 

__global__ void foo(int *results, int *constBuf) 
{ 
    int tdx = threadIdx.x; 
    int idx = blockIdx.x * blockDim.x + tdx; 

    if(idx < N) 
    { 
     results[idx] = constBuf[idx]; 
    } 
} 

// main routine that executes on the host 
int main(int argc, char* argv[]) 
{ 
    int *results_h = new int[N]; 
    int *results_d = NULL; 

    cudaMalloc((void **)&results_d, N*sizeof(int)); 

    int arr[10] = { 16, 2, 77, 40, 12, 3, 5, 3, 6, 6 }; 

    int *cpnt; 
    cudaError_t err = cudaGetSymbolAddress((void **)&cpnt, "constBuf_d"); 

    if(err) 
     cout << "error!"; 

    cudaMemcpyToSymbol((void**)&cpnt, arr, N*sizeof(int), 0, cudaMemcpyHostToDevice); 

    foo <<< 1, 256 >>> (results_d, cpnt); 

    cudaMemcpy(results_h, results_d, N*sizeof(int), cudaMemcpyDeviceToHost); 

    for(int i=0; i < N; ++i) 
     printf("%i ", results_h[i]); 
} 

出於某種原因,我只在result_h中得到「0」。我使用能力爲1.1的卡片運行CUDA 4.0。

任何想法?謝謝!

回答

7

如果您在代碼中添加了適當的錯誤檢查,您會發現cudaMemcpyToSymbol失敗並出現無效的設備符號錯誤。您需要按名稱傳遞符號,或者使用cudaMemcpy代替。所以這個:

cudaGetSymbolAddress((void **)&cpnt, "constBuf_d"); 
cudaMemcpy(cpnt, arr, N*sizeof(int), cudaMemcpyHostToDevice); 

cudaMemcpyToSymbol("constBuf_d", arr, N*sizeof(int), 0, cudaMemcpyHostToDevice); 

cudaMemcpyToSymbol(constBuf_d, arr, N*sizeof(int), 0, cudaMemcpyHostToDevice); 

會工作。儘管如此,將一個常量內存地址作爲參數傳遞給內核是使用常量內存的錯誤方式 - 它會使編譯器無法通過常量內存高速緩存生成訪問內存的指令。比較計算能力爲1.2 PTX爲內核生成的:

.entry _Z3fooPiS_ (
     .param .u32 __cudaparm__Z3fooPiS__results, 
     .param .u32 __cudaparm__Z3fooPiS__constBuf) 
    { 
    .reg .u16 %rh<4>; 
    .reg .u32 %r<12>; 
    .reg .pred %p<3>; 
    .loc 16 7 0 
$LDWbegin__Z3fooPiS_: 
    mov.u16  %rh1, %ctaid.x; 
    mov.u16  %rh2, %ntid.x; 
    mul.wide.u16 %r1, %rh1, %rh2; 
    cvt.s32.u16  %r2, %tid.x; 
    add.u32  %r3, %r2, %r1; 
    mov.u32  %r4, 9; 
    setp.gt.s32  %p1, %r3, %r4; 
    @%p1 bra $Lt_0_1026; 
    .loc 16 14 0 
    mul.lo.u32 %r5, %r3, 4; 
    ld.param.u32 %r6, [__cudaparm__Z3fooPiS__constBuf]; 
    add.u32  %r7, %r6, %r5; 
    ld.global.s32 %r8, [%r7+0]; 
    ld.param.u32 %r9, [__cudaparm__Z3fooPiS__results]; 
    add.u32  %r10, %r9, %r5; 
    st.global.s32 [%r10+0], %r8; 
$Lt_0_1026: 
    .loc 16 16 0 
    exit; 
$LDWend__Z3fooPiS_: 
    } // _Z3fooPiS_ 

與此內核:

__global__ void foo2(int *results) 
{ 
    int tdx = threadIdx.x; 
    int idx = blockIdx.x * blockDim.x + tdx; 

    if(idx < N) 
    { 
     results[idx] = constBuf_d[idx]; 
    } 
} 

產生

.entry _Z4foo2Pi (
     .param .u32 __cudaparm__Z4foo2Pi_results) 
    { 
    .reg .u16 %rh<4>; 
    .reg .u32 %r<12>; 
    .reg .pred %p<3>; 
    .loc 16 18 0 
$LDWbegin__Z4foo2Pi: 
    mov.u16  %rh1, %ctaid.x; 
    mov.u16  %rh2, %ntid.x; 
    mul.wide.u16 %r1, %rh1, %rh2; 
    cvt.s32.u16  %r2, %tid.x; 
    add.u32  %r3, %r2, %r1; 
    mov.u32  %r4, 9; 
    setp.gt.s32  %p1, %r3, %r4; 
    @%p1 bra $Lt_1_1026; 
    .loc 16 25 0 
    mul.lo.u32 %r5, %r3, 4; 
    mov.u32  %r6, constBuf_d; 
    add.u32  %r7, %r5, %r6; 
    ld.const.s32 %r8, [%r7+0]; 
    ld.param.u32 %r9, [__cudaparm__Z4foo2Pi_results]; 
    add.u32  %r10, %r9, %r5; 
    st.global.s32 [%r10+0], %r8; 
$Lt_1_1026: 
    .loc 16 27 0 
    exit; 
$LDWend__Z4foo2Pi: 
    } // _Z4foo2Pi 

注意,在第二種情況下,constBuf_d通過ld.const.s32訪問而不是ld.global.s32,因此使用常量內存緩存。

3

優秀答案@talonmies。但我想提一下cuda 5中的變化。在函數MemcpyToSymbol()中,不再支持char *參數。

的CUDA 5發行說明讀:

** The use of a character string to indicate a device symbol, which was possible with certain API functions, is no longer supported. Instead, the symbol should be used directly. 

相反副本必須將常數存儲器可以製備如下:

cudaMemcpyToSymbol(dev_x, x, N * sizeof(float)); 

在這種情況下「dev_x」是指向常數存儲而「x」是指向需要複製到dev_x的主機內存的指針。

相關問題