CUDA将继承的类对象复制到设备

时间:2016-11-18 16:45:07

标签: c++ pointers inheritance cuda copy

我有一个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);

我已经看到多个类似的问题hereherehereherehere,但要么我无法理解他们的问题有或者似乎不符合这个特殊问题。

我知道我得到的分段错误是因为gpuClass->par在设备上,而cudaMemCpy不允许设备指针。但是,我认为没有其他方法可以将指针“插入”gpuClass对象。

我能看到解决方案的方法是:

1)展平我的数据结构。但是,我不知道如何使用我想要的继承类功能执行此操作。

2)最初在gpu上实例化gpuClass,我不知道该怎么做,或者

3)我在one of the solutions中看到你可以使用cudaMemCpy将动态分配列表的地址复制到一个对象中,但我又一次不知道如何这样做(特别是将设备指针复制到另一个设备指针的位置)。

非常感谢任何帮助。

1 个答案:

答案 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
$