__device__变量上的cudaMemcpyFromSymbol

时间:2014-09-27 15:00:34

标签: cuda gpu gpgpu

我正在尝试在__device__变量上应用内核函数,根据规范,它在全局内存中驻留""

#include <stdio.h>
#include "sys_data.h"
#include "my_helper.cuh"
#include "helper_cuda.h"
#include <cuda_runtime.h>


double X[10] = {1,-2,3,-4,5,-6,7,-8,9,-10};
double Y[10] = {0};
__device__ double DEV_X[10];


int main(void) {
    checkCudaErrors(cudaMemcpyToSymbol(DEV_X, X,10*sizeof(double)));
    vector_projection<double><<<1,10>>>(DEV_X, 10);
    getLastCudaError("oops");
    checkCudaErrors(cudaMemcpyFromSymbol(Y, DEV_X, 10*sizeof(double)));
    return 0;
}

核心函数vector_projectionmy_helper.cuh中定义如下:

template<typename T> __global__ void vector_projection(T *dx, int n) {
    int tid;
    tid = threadIdx.x + blockIdx.x * blockDim.x;
    if (tid < n) {
        if (dx[tid] < 0)
            dx[tid] = (T) 0;
    }
}

如您所见,我使用cudaMemcpyToSymbolcudaMemcpyFromSymbol与设备之间传输数据。但是,我收到以下错误:

CUDA error at ../src/vectorAdd.cu:19 code=4(cudaErrorLaunchFailure) 
  "cudaMemcpyFromSymbol(Y, DEV_X, 10*sizeof(double))" 

脚注:我当然可以避免使用__device__个变量,然后选择能正常工作的like this;我只想看看如何用__device__变量做同样的事情(如果可能的话)。

更新cuda-memcheck的输出可在http://pastebin.com/AW9vmjFs找到。我得到的错误消息如下:

========= Invalid __global__ read of size 8
=========     at 0x000000c8 in /home/ubuntu/Test0001/Debug/../src/my_helper.cuh:75:void vector_projection<double>(double*, int)
=========     by thread (9,0,0) in block (0,0,0)
=========     Address 0x000370e8 is out of bounds

1 个答案:

答案 0 :(得分:6)

问题的根源在于你是not allowed to take the address of a device variable in ordinary host code

vector_projection<double><<<1,10>>>(DEV_X, 10);
                                    ^

虽然这似乎可以正确编译,但传递的实际地址是垃圾。

要在主机代码中获取设备变量的地址,我们可以使用cudaGetSymbolAddress

这是一个为我编译和运行正常的实例:

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

double X[10] = {1,-2,3,-4,5,-6,7,-8,9,-10};
double Y[10] = {0};
__device__ double DEV_X[10];

template<typename T> __global__ void vector_projection(T *dx, int n) {
    int tid;
    tid = threadIdx.x + blockIdx.x * blockDim.x;
    if (tid < n) {
        if (dx[tid] < 0)
            dx[tid] = (T) 0;
    }
}



int main(void) {
    cudaMemcpyToSymbol(DEV_X, X,10*sizeof(double));
    double *my_dx;
    cudaGetSymbolAddress((void **)&my_dx, DEV_X);
    vector_projection<double><<<1,10>>>(my_dx, 10);
    cudaMemcpyFromSymbol(Y, DEV_X, 10*sizeof(double));
    for (int i = 0; i < 10; i++)
      printf("%d: %f\n", i, Y[i]);
    return 0;
}
$ nvcc -arch=sm_35 -o t577 t577.cu
$ cuda-memcheck ./t577
========= CUDA-MEMCHECK
0: 1.000000
1: 0.000000
2: 3.000000
3: 0.000000
4: 5.000000
5: 0.000000
6: 7.000000
7: 0.000000
8: 9.000000
9: 0.000000
========= ERROR SUMMARY: 0 errors
$

这不是解决这个问题的唯一方法。在设备代码中获取设备变量的地址是合法的,因此您可以使用以下行来修改内核:

T *dx = DEV_X;

并放弃将设备变量作为内核参数传递。根据评论中的建议,您还可以修改代码以使用Unified Memory

关于错误检查,如果您偏离proper cuda error checking并且在偏差方面不小心,结果可能会令人困惑。除了由自己的行为引起的错误之外,大多数cuda API调用都可以返回由于某些先前的CUDA异步活动(通常是内核调用)而导致的错误。