Cuda对象副本

时间:2018-04-17 12:40:09

标签: object cuda memcpy

我试图将CUDA与对象一起使用,这是一个小测试代码,我把它们放在一起试用,但我遇到了一个问题。当我对变量的设备版本执行任何操作时,复制回主机失败并显示" cuda错误Ilegal Address",但如果我只是将代码复制到设备并返回它的工作原理。 如果我注释掉printf ...行,那就行了。

class A {
public:
    int s;
};

__device__ A *d_a;
__global__ void MethodA() {
    printf("%d\n", d_a->s);
}

int main() {
    A *a = new A();
    a->s = 10;

    cudaError e;
    e = cudaMalloc((void**)&d_a, sizeof(A));
    e = cudaMemcpy(d_a, a, sizeof(A), cudaMemcpyHostToDevice);
    MethodA << <1, 1 >> > ();
    e = cudaMemcpy(a, d_a, sizeof(A), cudaMemcpyDeviceToHost);
    std::cout << cudaGetErrorName(e) << std::endl;

    delete(a);
    std::getchar();
    return 0;
}

1 个答案:

答案 0 :(得分:1)

使用__device__变量会造成困难。它旨在用于编译时已知的静态分配。

如果您使用普通的基于主机的指针,指向在运行时创建的动态分配(您正在进行此操作),然后通过内核参数将该基于主机的指针传递给设备,那么您的方法将会简化

您的方法存在一些问题:

  1. 您使用的API不正确,无法修改__device__变量。我们不使用cudaMemcpy。我们使用cudaMemcpyToSymbol

  2. 您不能在主机代码中获取设备实体的地址:

    e = cudaMalloc((void**)&d_a, sizeof(A));
                           ^
    

    cudaMalloc期望将分配的指针值存储在主机内存中,而不是存储在设备内存中。它将指向设备内存中的位置,但应将其存储在主机变量中。

  3. 如果您想继续使用您的方法,以下修改应该使其正确:

    $ cat t89.cu
    #include <iostream>
    #include <stdio.h>
    
    class A {
    public:
        int s;
    };
    
    __device__ A *d_a;
    __global__ void MethodA() {
        printf("%d\n", d_a->s);
    }
    
    int main() {
        A *a = new A();
        a->s = 10;
        A *temp_d_a;
        cudaMalloc((void**)&temp_d_a, sizeof(A));
        cudaMemcpy(temp_d_a, a, sizeof(A), cudaMemcpyHostToDevice);
        cudaMemcpyToSymbol(d_a, &temp_d_a, sizeof(A *));
        MethodA << <1, 1 >> > ();
        cudaMemcpy(a, temp_d_a, sizeof(A), cudaMemcpyDeviceToHost);
        std::cout << cudaGetErrorString(cudaGetLastError()) << std::endl;
        cudaFree(temp_d_a);
        delete(a);
        return 0;
    }
    $ nvcc t89.cu -o t89
    $ cuda-memcheck ./t89
    ========= CUDA-MEMCHECK
    10
    no error
    ========= ERROR SUMMARY: 0 errors
    $
    

    编辑:关于我之前的发言:

      

    如果您使用普通的基于主机的指针,指向在运行时创建的动态分配(您正在进行此操作),然后通过内核参数将该基于主机的指针传递给设备,那么您的方法将会简化

    并在下面的评论中询问,这是一个显示该方法的有效例子:

    $ cat t89.cu
    #include <iostream>
    #include <stdio.h>
    
    class A {
    public:
        int s;
    };
    
    __global__ void MethodA(A *a) {
        printf("%d\n", a->s);
    }
    
    int main() {
        A *a = new A();
        a->s = 10;
        A *d_a;  //  an ordinary host-based pointer
        cudaMalloc((void**)&d_a, sizeof(A)); //dynamic allocation created at runtime
        cudaMemcpy(d_a, a, sizeof(A), cudaMemcpyHostToDevice);
        MethodA << <1, 1 >> > (d_a);  // passed to kernel via parameter
        cudaMemcpy(a, d_a, sizeof(A), cudaMemcpyDeviceToHost);
        std::cout << cudaGetErrorString(cudaGetLastError()) << std::endl;
        cudaFree(d_a);
        delete(a);
        return 0;
    }
    $ nvcc -o t89 t89.cu
    $ cuda-memcheck ./t89
    ========= CUDA-MEMCHECK
    10
    no error
    ========= ERROR SUMMARY: 0 errors
    $