CUDA:一个结构内部结构的数组的分配(CUDA: allocation of an array o

2019-06-26 21:58发布

我有以下结构:

typedef struct neuron
{
float*  weights;
int n_weights;
}Neuron;


typedef struct neurallayer
{
Neuron *neurons;
int    n_neurons;
int    act_function;
}NLayer;

“n图层”结构可以包含“神经元”的任意数量的

我试图分配一个“n图层”结构与5以这种方式从主机“神经元”:

NLayer* nL;
int i;
int tmp=9;
cudaMalloc((void**)&nL,sizeof(NLayer));
cudaMalloc((void**)&nL->neurons,6*sizeof(Neuron));
for(i=0;i<5;i++)
    cudaMemcpy(&nL->neurons[i].n_weights,&tmp,sizeof(int),cudaMemcpyHostToDevice);

......然后我试图修改“NL->神经元[0] .n_weights”变量与内核:

__global__ void test(NLayer* n)
           {
              n->neurons[0].n_weights=121;
           }

但在编译时NVCC返回该“警告”与内核无关的唯一行:

Warning: Cannot tell what pointer points to, assuming global memory space

当内核完成其工作的结构开始无法访问。

这很可能是我做的分配过程中一些错误....有人能帮助我吗? 非常感谢,并为我的英语对不起! :)

更新:

由于奥兰我修改我的代码创建这个函数应该分配结构“n图层”的一个实例:

NLayer* setNLayer(int numNeurons,int weightsPerNeuron,int act_fun)
{
    int i;
    NLayer  h_layer;
    NLayer* d_layer;
    float*  d_weights;

    //SET THE LAYER VARIABLE OF THE HOST NLAYER
    h_layer.act_function=act_fun;
    h_layer.n_neurons=numNeurons;
    //ALLOCATING THE DEVICE NLAYER
    if(cudaMalloc((void**)&d_layer,sizeof(NLayer))!=cudaSuccess)
        puts("ERROR: Unable to allocate the Layer");
    //ALLOCATING THE NEURONS ON THE DEVICE
    if(cudaMalloc((void**)&h_layer.neurons,numNeurons*sizeof(Neuron))!=cudaSuccess)
        puts("ERROR: Unable to allocate the Neurons of the Layer");
    //COPING THE HOST NLAYER ON THE DEVICE
    if(cudaMemcpy(d_layer,&h_layer,sizeof(NLayer),cudaMemcpyHostToDevice)!=cudaSuccess)
                puts("ERROR: Unable to copy the data layer onto the device");

    for(i=0;i<numNeurons;i++)
    {
        //ALLOCATING THE WEIGHTS' ARRAY ON THE DEVICE
        cudaMalloc((void**)&d_weights,weightsPerNeuron*sizeof(float));
        //COPING ITS POINTER AS PART OF THE i-TH NEURONS STRUCT
        if(cudaMemcpy(&d_layer->neurons[i].weights,&d_weights,sizeof(float*),cudaMemcpyHostToDevice)!=cudaSuccess)
                puts("Error: unable to copy weights' pointer to the device");
    }


    //RETURN THE DEVICE POINTER
    return d_layer;
}

我呼吁从主该功能以这种方式(内核“测试”是先前声明):

int main()
{
    NLayer* nL;
    int h_tmp1;
    float h_tmp2;

    nL=setNLayer(10,12,13);
    test<<<1,1>>>(nL);
    if(cudaMemcpy(&h_tmp1,&nL->neurons[0].n_weights,sizeof(float),cudaMemcpyDeviceToHost)!=cudaSuccess);
        puts("ERROR!!");
    printf("RESULT:%d",h_tmp1);

}

当我编译代码编译器给我的警告,当我执行程序将其打印在屏幕上:

Error: unable to copy weights' pointer to the device
Error: unable to copy weights' pointer to the device
Error: unable to copy weights' pointer to the device
Error: unable to copy weights' pointer to the device
Error: unable to copy weights' pointer to the device
Error: unable to copy weights' pointer to the device
Error: unable to copy weights' pointer to the device
Error: unable to copy weights' pointer to the device
Error: unable to copy weights' pointer to the device
Error: unable to copy weights' pointer to the device
ERROR!!
RESULT:1

最后一个错误,如果我评论内核调用不不能比拟的。

我哪里错了? 我不知道该怎么对你的帮助做的感谢!

Answer 1:

问题就在这里:

cudaMalloc((void**)&nL,sizeof(NLayer));
cudaMalloc((void**)&nL->neurons,6*sizeof(Neuron));

在第一行中, nL指向在全局存储器来构造在设备上。 因此,在第二行的第一个参数cudaMalloc是驻留在GPU,这是不确定的行为地址(我的测试系统上,它会导致段错误;在你的情况下,虽然,有一些更微妙的)。

做你想做什么正确的方法是先在主内存中创建结构,用数据填充它,然后将其复制到设备,就像这样:

NLayer* nL;
NLayer h_nL;
int i;
int tmp=9;
// Allocate data on device
cudaMalloc((void**)&nL, sizeof(NLayer));
cudaMalloc((void**)&h_nL.neurons, 6*sizeof(Neuron));
// Copy nlayer with pointers to device
cudaMemcpy(nL, &h_nL, sizeof(NLayer), cudaMemcpyHostToDevice);

另外,不要忘记常检查来自CUDA程序的任何错误。

UPDATE

在你的代码的第二个版本:

cudaMemcpy(&d_layer->neurons[i].weights,&d_weights,...) ---再次,你正在解除引用设备指针( d_layer上主机)。 相反,你应该使用

cudaMemcpy(&h_layer.neurons[i].weights,&d_weights,sizeof(float*),cudaMemcpyHostToDevice

在这里,你采取h_layer (主结构),读取其元件( h_layer.neurons ),它是指向设备存储器中。 然后,你做一些指针算术就可以了( &h_layer.neurons[i].weights )。 需要到设备内存中没有访问计算该地址。



Answer 2:

这一切都取决于你的使用GPU卡上。 费米显卡采用统一的寻址共享和全局内存空间,而前期费米的卡没有。

对于预费米的情况下,你不知道该地址是共享还是全球性的。 编译器通常可以算出来,但也有它不可的情况。 当需要一个指向共享存储器,则通常需要共享变量的地址,编译器可以识别此。 “假设全球”的消息,这是没有明确规定的时候会出现。

如果您使用的是具有2.x或更高的计算capabiilty一个GPU,它应与-arch = sm_20编译器标志工作



文章来源: CUDA: allocation of an array of structs inside a struct