我正在尝试创建一个将在设备上分配的类。我希望构造函数在设备上运行,以便包含内部字段的整个对象在设备上自动分配,而不必创建宿主对象,然后手动将其复制到设备。
我正在使用推送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(推力),但这不起作用,有人可以向我解释原因吗?
欢呼求助
答案 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中会有一个方法或功能让你直接在设备上初始化对象,因此构造函数(或其他地方)中的任何动态分配数据也会在设备上分配,而不是手动复制每一块内存的繁琐方法。