Object CUDA对象从设备复制到主机

Object CUDA对象从设备复制到主机,object,cuda,memcpy,Object,Cuda,Memcpy,我正在尝试将一个对象从设备复制回主机,它可以工作,但是如果该对象包含指向某个对象的指针,我就找不到调用cudaMemcpy的正确方法 这是一个简单的代码来显示我正在尝试做什么。cudaMemcpy返回cudaSuccess,但temp变量保持“空” A类{ 公众: int*s; }; __全局无效方法A(A*A){ printf(“%d\n”,a->s[2]); } int main(){ A*A=新的A(); int asd[]={0,1,2,3,4}; a->s=asd; A*d_A; Cu

我正在尝试将一个对象从设备复制回主机,它可以工作,但是如果该对象包含指向某个对象的指针,我就找不到调用cudaMemcpy的正确方法

这是一个简单的代码来显示我正在尝试做什么。cudaMemcpy返回cudaSuccess,但temp变量保持“空”

A类{
公众:
int*s;
};
__全局无效方法A(A*A){
printf(“%d\n”,a->s[2]);
}
int main(){
A*A=新的A();
int asd[]={0,1,2,3,4};
a->s=asd;
A*d_A;
Cudamaloc((void**)和d_a,sizeof(a));
cudaMemcpy(d_a,a,sizeof(a),cudamemcpyhostodevice);
内部*温度;
cudaError e;
e=Cudamaloc((空心**)和温度,尺寸(内部)*5;
e=cudaMemcpy(温度,a->s,大小f(int)*5,cudaMemcpyHostToDevice);
e=cudaMemcpy(&(d_a->s),&temp,sizeof(int*),cudaMemcpyHostToDevice);
方法a>(d_a);
cudaMemcpy(a,d_a,sizeof(a),cudamemcpydevicetoost);
e=cudaMemcpy(&temp,a->s,sizeof(int)*5,cudaMemcpyDeviceToHost);
a->s=温度;
库达弗里(杜阿);
删除(a);
返回0;
}
问题在于:

e = cudaMemcpy(&(d_a->s), &temp, sizeof(int*), cudaMemcpyHostToDevice);
d_a
是指向设备对象的指针,您不能在主机上取消对它的引用。 您必须首先将
s
复制到设备,然后在主机上创建一个
A
类型的对象,该对象具有指向
s
设备副本的指针,然后在设备上复制此对象

这是CUDA的一个已知问题,并且经常发生在链表或树之类的结构中,这也是Nvidia投入大量精力改进的原因之一。如果您可以使用它,并且它不会降低应用程序的性能,那么它可以为您节省很多类似问题的麻烦

以下是您解决问题的示例:

class A {
public:
    int *s;
};

__global__ void MethodA(A *a) {
    printf("%d\n", a->s[2]);
    a->s[2] = 6;
}

int main() {
    A *a = new A();
    int asd[] = { 0, 1, 2, 3, 4 };
    a->s = asd;

    A *a_with_d_s = new A();
    cudaMalloc(&(a_with_d_s->s), sizeof(int) * 5);
    cudaMemcpy(a_with_d_s->s, a->s, sizeof(int) * 5, cudaMemcpyHostToDevice);

    A *d_a;
    cudaMalloc(&d_a, sizeof(A));
    cudaMemcpy(d_a, a_with_d_s, sizeof(A), cudaMemcpyHostToDevice);

    MethodA << <1, 1 >> > (d_a);

    // note that if we call the following line, a->s will point to device
    // memory!
    //cudaMemcpy(a, d_a, sizeof(A), cudaMemcpyDeviceToHost);
    cudaMemcpy(a->s, a_with_d_s->s, sizeof(int) * 5, cudaMemcpyDeviceToHost);

    printf("%d\n", a->s[2]);

    cudaFree(d_a);
    cudaFree(a_with_d_s->s);

    delete(a);
    delete(a_with_d_s);
    return 0;
}

如果要复制整个对象,请执行
cudaMemcpy(a,d_a,sizeof(a),cudaMemcpyDeviceToHost)这个,不会像你说的那样工作。如果我将它复制到另一个变量,而不是“合并”这两个变量,那么它是有效的,但是有没有更好的方法呢?我也想添加到您的答案中,因为如果
a
包含
s
以外的字段,它就不会复制这些字段。用_d_s
将它们复制到a_解决了这个问题。@TóthBence我不知道还有比你更好的方法-这里的问题是你需要对一个对象进行深度复制。即使您不需要担心分布式内存场景,这也不是小事。C++通过阻止手动管理内存来解决问题,而定义了一组标准容器(如<代码> STD::vector < /COD>和<代码> STD::数组< /代码>)来代替。然而,(AFAIK),标准C++库在CUDA代码中不起作用。有,你可以用它来代替,但我不是这方面的专家。谢谢,我已经读了一些关于推力的文章,但我认为它对复制没有帮助。
class A {
public:
    int *s;
};

__global__ void MethodA(A *a) {
    printf("%d\n", a->s[2]);
    a->s[2] = 6;
}

int main() {
    A *a = new A();
    int asd[] = { 0, 1, 2, 3, 4 };
    a->s = asd;

    A *a_with_d_s = new A();
    cudaMalloc(&(a_with_d_s->s), sizeof(int) * 5);
    cudaMemcpy(a_with_d_s->s, a->s, sizeof(int) * 5, cudaMemcpyHostToDevice);

    A *d_a;
    cudaMalloc(&d_a, sizeof(A));
    cudaMemcpy(d_a, a_with_d_s, sizeof(A), cudaMemcpyHostToDevice);

    MethodA << <1, 1 >> > (d_a);

    // note that if we call the following line, a->s will point to device
    // memory!
    //cudaMemcpy(a, d_a, sizeof(A), cudaMemcpyDeviceToHost);
    cudaMemcpy(a->s, a_with_d_s->s, sizeof(int) * 5, cudaMemcpyDeviceToHost);

    printf("%d\n", a->s[2]);

    cudaFree(d_a);
    cudaFree(a_with_d_s->s);

    delete(a);
    delete(a_with_d_s);
    return 0;
}
2
6