我有一个Parent
类和一个继承的Child
类:
class Parent {};
class Child : public Parent {};
有几个子类继承自Parent
,但为简单起见,我只包括一个。这些继承的类对于我正在处理的项目是必需的。我还有一个来自另一个类的对象,我希望将其复制到设备上:
class CopyClass {
public:
Parent ** par;
};
请注意,Parent ** par;
存在,因为我需要有一个Child
个对象的列表,但将使用哪个子级(以及列表的长度)在编译时是未知的。我试图将CopyClass
对象复制到设备上:
int length = 5;
//Instantiate object on the CPU
CopyClass cpuClass;
cpuClass.par = new Parent*[length];
for(int i = 0; i < length; ++i) cpuClass.par[i] = new Child;
//Copy object onto GPU
CopyClass * gpuClass;
cudaMalloc(&gpuClass,sizeof(CopyClass));
cudaMemcpy(gpuClass,&cpuClass,sizeof(CopyClass),cudaMemcpyHostToDevice);
//Copy dynamically allocated variables to GPU
Parent ** d_par;
d_par = new Parent*[length];
for(int i = 0; i < length; ++i) {
cudaMalloc(&d_par[i],sizeof(Child));
printf("\tCopying data\n");
cudaMemcpy(d_par[i],cpuClass.par[i],sizeof(Child),cudaMemcpyHostToDevice);
}
//SIGSEGV returned during following operation
cudaMemcpy(gpuClass->par,d_par,length*sizeof(void*),cudaMemcpyHostToDevice);
我已经看到多个类似的问题here,here,here,here和here,但要么我无法理解他们的问题有或者似乎不符合这个特殊问题。
我知道我得到的分段错误是因为gpuClass->par
在设备上,而cudaMemCpy不允许设备指针。但是,我认为没有其他方法可以将指针“插入”gpuClass
对象。
我能看到解决方案的方法是:
1)展平我的数据结构。但是,我不知道如何使用我想要的继承类功能执行此操作。
2)最初在gpu上实例化gpuClass
,我不知道该怎么做,或者
3)我在one of the solutions中看到你可以使用cudaMemCpy将动态分配列表的地址复制到一个对象中,但我又一次不知道如何这样做(特别是将设备指针复制到另一个设备指针的位置)。
非常感谢任何帮助。
答案 0 :(得分:1)
在first related link中,我为基于对象的深层复制序列提供了5个步骤,但是由于您正在对该链接中给出的示例执行双指针版本,这种情况很复杂。 The complexity associated with a double-pointer deep-copy is such that the usual recommendation is to avoid it(即展平)。
我们需要对您的代码进行的第一个修复是正确处理d_par
数组。您需要在设备上进行相应的分配以保存与d_par
关联的阵列。与d_par
关联的数组具有5个对象指针的存储空间。您已为其分配了主机端存储(使用new
)但您无处为其进行设备端分配。 (我不是在谈论d_par
指针本身,我在谈论它指向的内容,这是一个5的数组指针)。
我们需要做的第二个修复是在顶级设备端对象中调整par
指针本身的修正(而不是它所指向的)。您试图将这两者合并为一个步骤,但这不会起作用。
以下是您的代码的修改版本,似乎可以正常使用上述更改:
$ cat t29.cu
#include <stdio.h>
class Parent {public: int my_id;};
class Child : public Parent {};
class CopyClass {
public:
Parent ** par;
};
const int length = 5;
__global__ void test_kernel(CopyClass *my_class){
for (int i = 0; i < length; i++)
printf("object: %d, id: %d\n", i, my_class->par[i]->my_id);
}
int main(){
//Instantiate object on the CPU
CopyClass cpuClass;
cpuClass.par = new Parent*[length];
for(int i = 0; i < length; ++i) {
cpuClass.par[i] = new Child;
cpuClass.par[i]->my_id = i+1;} // so we can prove that things are working
//Allocate storage for object onto GPU and copy host object to device
CopyClass * gpuClass;
cudaMalloc(&gpuClass,sizeof(CopyClass));
cudaMemcpy(gpuClass,&cpuClass,sizeof(CopyClass),cudaMemcpyHostToDevice);
//Copy dynamically allocated child objects to GPU
Parent ** d_par;
d_par = new Parent*[length];
for(int i = 0; i < length; ++i) {
cudaMalloc(&d_par[i],sizeof(Child));
printf("\tCopying data\n");
cudaMemcpy(d_par[i],cpuClass.par[i],sizeof(Child),cudaMemcpyHostToDevice);
}
//Copy the d_par array itself to the device
Parent ** td_par;
cudaMalloc(&td_par, length * sizeof(Parent *));
cudaMemcpy(td_par, d_par, length * sizeof(Parent *), cudaMemcpyHostToDevice);
//copy *pointer value* of td_par to appropriate location in top level object
cudaMemcpy(&(gpuClass->par),&(td_par),sizeof(Parent **),cudaMemcpyHostToDevice);
test_kernel<<<1,1>>>(gpuClass);
cudaDeviceSynchronize();
return 0;
}
$ nvcc -arch=sm_61 -o t29 t29.cu
$ cuda-memcheck ./t29
========= CUDA-MEMCHECK
Copying data
Copying data
Copying data
Copying data
Copying data
object: 0, id: 1
object: 1, id: 2
object: 2, id: 3
object: 3, id: 4
object: 4, id: 5
========= ERROR SUMMARY: 0 errors
$