我正在尝试将一些POD传递给一个内核,该内核具有一些非POD作为参数,并且具有非显式构造函数。其背后的想法是:在主机上分配一些内存,将内存传递给内核,并将内存封装在对象中,而无需用户明确地执行该步骤。
构造函数被标记为__device__代码,但在传递参数时不会调用它们,我无法弄清楚原因。
我的问题并不是真的与我应该怎么做,而是试图了解幕后发生的事情。
这里有一个例子(我使用的是具有2.1能力的GPU的CUDA 5,因此是printf)。
#include <stdio.h>
struct Test {
__device__ Test() {
printf("Default\n"),
_n = 0;
}
__device__ Test(int n) {
printf("Construct %d\n", n);
_n = n;
}
__device__ Test(const Test &t) {
printf("Copy constr %d\n", t._n);
_n = t._n;
}
__device__ Test &operator=(const Test &t) {
printf("Assignment %d\n", t._n);
_n = t._n;
return *this;
}
__device__ int calc() const {
printf("Calculating %d\n", threadIdx.x + 10 * _n);
return threadIdx.x + 10 * _n;
}
int _n;
};
__global__ void dosome(Test a, Test b) {
printf("Kernel data %d %d\n", a._n, b._n);
a.calc();
b.calc();
}
int main(int argc, char **argv) {
dosome<<<1, 2>>>(2, 3);
cudaError_t cudaerr = cudaDeviceSynchronize();
if (cudaerr != cudaSuccess)
printf("kernel launch failed with error:\n\t%s\n",cudaGetErrorString(cudaerr));
return 0;
}
编辑:忘了说,没有打印构造函数消息,但是calc和内核消息都是。
EDIT2:是否保证CUDA在在设备上复制之前初始化一个Test对象?
答案 0 :(得分:4)
你必须像普通方法一样看到构造函数。如果您使用__host__
符合条件,那么您就可以将其称为主机端。如果您使用__device__
符合条件,则可以将其称为设备端。如果你同时使用两者,你就可以双方打电话。
执行dosome<<<1, 2>>>(2, 3);
时会发生什么情况是这两个对象是隐含构造的(因为你的构造函数不是explicit
,所以也许这会使你感到困惑)主持人然后memcpy
' d到设备。该过程中没有涉及复制构造函数。
让我们来说明一下:
__global__ void dosome(Test a, Test b) {
a.calc();
b.calc();
}
int main(int argc, char **argv) {
dosome<<<1, 2>>>(2, 3); // Constructors must be at least __host__
return 0;
}
// Outputs:
Construct 2 (from the host side)
Construct 3 (from the host side)
现在,如果您更改内核以取int
而不是Test
:
__global__ void dosome(int arga, int argb) {
// Constructors must be at least __device__
Test a(arga);
Test b(argb);
a.calc();
b.calc();
}
int main(int argc, char **argv) {
dosome<<<1, 2>>>(2, 3);
return 0;
}
// Outputs:
Construct 2 (from the device side)
Construct 3 (from the device side)
答案 1 :(得分:1)
好吧,如果我将__host__和__device__限定符都添加到构造函数中,我发现它有效(构造函数被调用)。对象的构造函数发生在主机端,然后它们被复制到设备(堆栈?)。这就是没有调用构造函数的原因:它们是设备代码(但在主机端调用的是什么?!)
在构造函数中同时使用__host__和__device__可以毫无问题地使用该类。
编辑:但是,我不确定在复制到设备之前是否总是发生构造。