CUDA对象从设备复制到主机
CUDA Object copy from device to host
我正在尝试将一个对象从设备复制回主机,它可以工作,但如果该对象包含指向某物的指针,我就找不到调用 cudaMemcpy 的正确方法。
这是一个简化的代码,用于展示我正在尝试做的事情。 cudaMemcpy returns 与 cudaSuccess 但临时变量保持 "empty".
class A {
public:
int *s;
};
__global__ void MethodA(A *a) {
printf("%d\n", a->s[2]);
}
int main() {
A *a = new A();
int asd[] = { 0, 1, 2, 3, 4 };
a->s = asd;
A *d_a;
cudaMalloc((void**)&d_a, sizeof(A));
cudaMemcpy(d_a, a, sizeof(A), cudaMemcpyHostToDevice);
int * temp;
cudaError e;
e = cudaMalloc((void**)&temp, sizeof(int) * 5);
e = cudaMemcpy(temp, a->s, sizeof(int) * 5, cudaMemcpyHostToDevice);
e = cudaMemcpy(&(d_a->s), &temp, sizeof(int*), cudaMemcpyHostToDevice);
MethodA << <1, 1 >> > (d_a);
cudaMemcpy(a, d_a, sizeof(A), cudaMemcpyDeviceToHost);
e = cudaMemcpy(&temp, a->s, sizeof(int) * 5, cudaMemcpyDeviceToHost);
a->s = temp;
cudaFree(d_a);
delete(a);
return 0;
}
问题出在这里:
e = cudaMemcpy(&(d_a->s), &temp, sizeof(int*), cudaMemcpyHostToDevice);
d_a
是指向设备对象的指针,您不能在主机上取消引用它。
您必须先将 s
复制到设备,然后在主机上创建一个 A
类型的对象,该对象具有指向 s
的设备副本的指针,然后复制该对象在设备上。
这是 CUDA 的一个已知问题,经常发生在链表或树等结构中,这也是 Nvidia 投入大量精力改进 unified memory 的原因之一。如果您可以使用它,并且它不会降低您的应用程序的性能,那么它可以为您省去很多此类问题的麻烦。
这是您的示例,已解决问题:
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
我正在尝试将一个对象从设备复制回主机,它可以工作,但如果该对象包含指向某物的指针,我就找不到调用 cudaMemcpy 的正确方法。
这是一个简化的代码,用于展示我正在尝试做的事情。 cudaMemcpy returns 与 cudaSuccess 但临时变量保持 "empty".
class A {
public:
int *s;
};
__global__ void MethodA(A *a) {
printf("%d\n", a->s[2]);
}
int main() {
A *a = new A();
int asd[] = { 0, 1, 2, 3, 4 };
a->s = asd;
A *d_a;
cudaMalloc((void**)&d_a, sizeof(A));
cudaMemcpy(d_a, a, sizeof(A), cudaMemcpyHostToDevice);
int * temp;
cudaError e;
e = cudaMalloc((void**)&temp, sizeof(int) * 5);
e = cudaMemcpy(temp, a->s, sizeof(int) * 5, cudaMemcpyHostToDevice);
e = cudaMemcpy(&(d_a->s), &temp, sizeof(int*), cudaMemcpyHostToDevice);
MethodA << <1, 1 >> > (d_a);
cudaMemcpy(a, d_a, sizeof(A), cudaMemcpyDeviceToHost);
e = cudaMemcpy(&temp, a->s, sizeof(int) * 5, cudaMemcpyDeviceToHost);
a->s = temp;
cudaFree(d_a);
delete(a);
return 0;
}
问题出在这里:
e = cudaMemcpy(&(d_a->s), &temp, sizeof(int*), cudaMemcpyHostToDevice);
d_a
是指向设备对象的指针,您不能在主机上取消引用它。
您必须先将 s
复制到设备,然后在主机上创建一个 A
类型的对象,该对象具有指向 s
的设备副本的指针,然后复制该对象在设备上。
这是 CUDA 的一个已知问题,经常发生在链表或树等结构中,这也是 Nvidia 投入大量精力改进 unified memory 的原因之一。如果您可以使用它,并且它不会降低您的应用程序的性能,那么它可以为您省去很多此类问题的麻烦。
这是您的示例,已解决问题:
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