直接在设备上创建包含字段的对象

时间:2013-04-18 11:56:40

标签: cuda thrust

我正在尝试创建一个将在设备上分配的类。我希望构造函数在设备上运行,以便包含内部字段的整个对象在设备上自动分配,而不必创建宿主对象,然后手动将其复制到设备。

我正在使用推送device_new

这是我的代码:

using namespace thrust;

class Particle
{
    public:
    int* data;

    __device__  Particle()
    {
        data = new int[10];
        for (int i=0; i<10; i++)
        {
            data[i] = i*2;
        }
    }
};


__global__ void test(Particle* p)
{
    for (int i=0; i<10; i++)
        printf("%d\n", p->data[i]);
}

int main() {

    device_ptr<Particle> p = device_new<Particle>();

    test<<<1,1>>>(thrust::raw_pointer_cast(p));


    cudaDeviceSynchronize();

    printf("Done!\n");

}

我使用__device__注释了构造函数并使用了device_new(推力),但这不起作用,有人可以向我解释原因吗?

欢呼求助

2 个答案:

答案 0 :(得分:4)

我相信答案在于here给出的描述。有人知道引擎盖下的推力可能会出现并指出这是否属实。

虽然自2009年以来推力发生了很大变化,但我相信device_new可能仍在使用某种形式的操作,其中对象实际上是在主机上临时实例化,然后复制到设备。我相信上述参考文献中描述的尺寸限制不再适用。

我能够让这个工作:

#include <stdio.h>
#include <thrust/device_ptr.h>
#include <thrust/device_new.h>

#define N 512

using namespace thrust;

class Particle
{
    public:
    int data[N];

    __device__ __host__  Particle()
    {
//        data = new int[10];
        for (int i=0; i<N; i++)
        {
            data[i] = i*2;
        }
    }
};


__global__ void test(Particle* p)
{
    for (int i=0; i<N; i++)
        printf("%d\n", p->data[i]);
}

int main() {

    device_ptr<Particle> p = device_new<Particle>();

    test<<<1,1>>>(thrust::raw_pointer_cast(p));


    cudaDeviceSynchronize();

    printf("Done!\n");

}

有趣的是,如果我省略了构造函数上的__host__装饰器,它会给出虚假结果,向我建议临时对象复制机制仍然存在。如果我切换到使用data而不是静态的动态分配,它还会给出虚假结果(以及cuda-memcheck报告越界访问错误),同时也向我建议device_new正在使用在主机上创建临时对象,然后复制到设备。

答案 1 :(得分:0)

首先感谢Rovert Crovella的投入(以及之前的答案)

所以显然我“高估了”device_new可以做什么,我认为它可以直接在设备上初始化对象,因此任何动态分配的内存也可以在设备上完成。

但似乎device_new基本上和手动方式一样:

Particle temp;
Particle *d_p;
cudaMalloc(&d_p, sizeof(Particle));
cudaMemcpy(d_p, &temp, sizeof(Particle), cudaMemcpyHostToDevice);

因此它创建了一个临时宿主对象并将其复制,就像手动完成一样。这意味着在对象内部分配的内存在主机上分配,只有指针被复制为对象的一部分,所以你不能在内核中使用那个内存,你必须手动将该内存复制到设备,并且推力没有似乎这样做。

因此,它只是创建临时主机对象并复制它的一种更简洁的方法,除非您无法复制内部分配的动态内存,因为您无权访问该临时变量。

我希望将来CUDA中会有一个方法或功能让你直接在设备上初始化对象,因此构造函数(或其他地方)中的任何动态分配数据也会在设备上分配,而不是手动复制每一块内存的繁琐方法。