2012-01-07 39 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的主机内存的指针。

相关问题