3

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

我正在使用推力 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_new (推力)注释了构造函数__device__,但这不起作用,有人可以向我解释为什么吗?

为帮助喝彩

4

2 回答 2

4

我相信答案就在此处给出的描述中。知道幕后推力的人可能会出现并指出这是否属实。

尽管自 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__装饰器,它会给出虚假的结果,这表明临时对象复制机制仍然存在。如果我切换到使用动态分配而不是静态分配,它还会给出虚假结果(并且 cuda-memcheck 报告越界访问错误)data,还建议我device_new在主机上使用临时对象创建,然后是副本到设备。

于 2013-04-18T14:27:21.627 回答
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 中会有一种方法或功能可以让您直接在设备上初始化对象,因此构造函数(或其他地方)中的任何动态分配的数据也可以在设备上分配,而不是繁琐的方式手动复制每一块内存。

于 2013-04-18T18:46:14.137 回答