【问题标题】:How to copy the pointer variable of a structure from host to device in cuda如何在cuda中将结构的指针变量从主机复制到设备
【发布时间】:2019-10-15 00:09:36
【问题描述】:

我有一个包含一些变量和一些指针变量的结构。 我想以两种不同的功能将此结构从主机复制到设备。在第一个函数中,我必须复制除一个指针变量之外的整个结构,然后在第二个函数中,我必须复制剩余的指针。

我能够复制整个结构,但无法复制第二个函数中剩余的指针变量。

#include<iostream>

#define cudaCheckErrors(msg) \
    do { \
        cudaError_t __err = cudaGetLastError(); \
        if (__err != cudaSuccess) { \
            fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
                msg, cudaGetErrorString(__err), \
                __FILE__, __LINE__); \
            fprintf(stderr, "*** FAILED - ABORTING\n"); \
            exit(1); \
        } \
    } while (0)

struct MultiSGDKernelParam {
  int count;
  size_t sizes;
  float *weights;
  float *mom; 
  float lrs;
};


__global__ void Launch(MultiSGDKernelParam *param, int N, MultiSGDKernelParam *result)
{
  for(int i=0; i<N; i++)
  {
     result[i] =param[i];     
  }
}

MultiSGDKernelParam *fillStructure(float *temp, const int N)
{       
    MultiSGDKernelParam *param;
        param = (MultiSGDKernelParam*) malloc( N * sizeof(MultiSGDKernelParam));
        for( int i=0; i< N ; i++)
        {
            param[i].count = i;
            param[i].sizes =  i*2;
            param[i].lrs =  param[i].sizes - i;
            param[i].weights = &temp[i];
        }

    std::cout<<"Inside the function"<<"\n"; 
        for(int i=0; i< N; i++)
        {
                std::cout<<param[i].sizes<<" ,"<<param[i].lrs<<"\t";
        }

    std::cout<<std::endl;   
        for(int i =0 ; i<N;i++)
        {
          std::cout<<*(param[i].weights)<<"\t";

        }
        std::cout<<std::endl;
    MultiSGDKernelParam *d_param;
        cudaMalloc((void**)&d_param, N  * sizeof(MultiSGDKernelParam));
        cudaMemcpy(d_param,param,N  * sizeof(MultiSGDKernelParam),cudaMemcpyHostToDevice);

    return d_param;

}

MultiSGDKernelParam * fillFullStructure(float *tweight, float *tmom,  const int N )
{
  MultiSGDKernelParam *param = fillStructure( tweight, N );

 /* float *d_mom;

   cudaMalloc((void**)&d_mom,N*sizeof(float));
   cudaCheckErrors("cudaMalloc1 fail");
   cudaMemcpy(d_mom,tmom,N*sizeof(float), cudaMemcpyHostToDevice);
   cudaCheckErrors("cudaMemcpy1 fail");*/
   for( int i=0; i< N ; i++)
        {
          cudaMemcpy(&(param[i].mom),&(tmom[i]),sizeof(float), cudaMemcpyHostToDevice);
      cudaCheckErrors("cudaMempcpy2 fail");
        }

    std::cout<<"Momentum Values copied"<<"\n";
   /*cudaMemcpy(&(param->mom),tmom,N*sizeof(float), cudaMemcpyHostToDevice);
   cudaCheckErrors("cudaMempcpy1fail");*/
   return param;
}



int main()
{
    static const  int N =5;
    float tempweight [N], tempmom[N] ;
    for(int i=0; i< N; i++)
    {
            tempweight[i] = i*3 +1;
        tempmom[i] = i+3;
    }

    MultiSGDKernelParam *result;
    MultiSGDKernelParam *param = fillFullStructure( tempweight,tempmom, N ); 
     const unsigned blocks = 1;
         const unsigned threadsPerBlock = 4;
    cudaMalloc(&result, N  * sizeof(MultiSGDKernelParam));
    Launch<<<blocks,threadsPerBlock>>>(param, N, result);
        cudaDeviceSynchronize();
    MultiSGDKernelParam *paramresult;
    paramresult = (MultiSGDKernelParam*) malloc( N * sizeof(MultiSGDKernelParam));
    cudaMemcpy(paramresult,result, N * sizeof(MultiSGDKernelParam),cudaMemcpyDeviceToHost);
    std::cout<<"Inside Main"<<"\n";
    for(int i=0; i< N; i++)
        {
           std::cout<<paramresult[i].sizes<<" ,"<<paramresult[i].lrs<<"\t";
        }
    std::cout<<std::endl;
    for(int i =0 ; i<N;i++)
    { 
          std::cout<<*(paramresult[i].weights)<<"\t";
          std::cout<<*(paramresult[i].mom)<<"\t";
    }
         std::cout<<std::endl;

    return 0;
}

输出为

Inside the function    
0 ,0    2 ,1    4 ,2    6 ,3    8 ,4    
1   4   7   10  13  
Momentum Values copied
Inside Main
0 ,0    2 ,1    4 ,2    6 ,3    8 ,4    
Segmentation fault (core dumped)

我的代码已编译但在打印值时出现分段错误。复制是否成功如果不是什么问题。

【问题讨论】:

  • 你已经用 CUDA 标记了这个,但我在你的代码中没有看到任何 CUDA 代码或 API
  • 用 cuda 重新发布了代码。
  • 运行时错误来自尝试访问param-&gt;mom,这是一个设备指针,在主机代码中无效。除此之外,很难告诉你要修复什么,因为你的复制代码背后的整个想法都被打破了
  • 你可能想学习this
  • 根据建议和提供的链接,我更新了代码并发布了结果。但仍然没有运气。我无法确定解决方案。请帮我解决问题。请提供带有完整代码的解决方案,以便更好地理解。提前致谢。

标签: c++ c cuda


【解决方案1】:
  • 我不建议这样编写 CUDA 内核:

    __global__ void Launch(MultiSGDKernelParam *param, int N, MultiSGDKernelParam *result)
    {
      for(int i=0; i<N; i++)
      {
         result[i] =param[i];     
      }
    }
    

    即使只是为了演示,你也应该做两件事之一:要么像那样编写内核(没有专门针对 CUDA 线程)并且只启动 1 个线程的 1 个块(那么很明显,这只是为了演示)或使用正确的 CUDA 线程索引(例如int i = threadIdx.x+blockDim.x*blockIdx.x;)并摆脱 for 循环,并使用多个线程启动您的块。就目前而言,您没有做过任何事情。您有一个没有专业化的普通 for 循环,在多个线程中运行。当然,这可能不是您的问题的重点,但是您现在的这种行为意味着线程在尝试写入result[i] 时将相互踩踏。即使您的所有其他代码都是正确的,这也可能会让人难以理解事情是否正常运行。我们将通过将您的启动配置切换为 &lt;&lt;&lt;1,1&gt;&gt;&gt;

    来解决此问题
  • 这个:

    param[i].weights = &temp[i];
    

    不可能是正确的。您正在结构内部设置一个指针以指向 主机内存 中的内容。 (这里的temp 项指向您的tempweight 主机数组。)这样的指针不能以任何方式在设备代码中使用。这是基本的 CUDA 原则。当您将该结构复制到设备时,该指针的数值不会以任何方式更改,这意味着它仍然指向主机内存。如果您打算在设备代码中的任何位置使用此指针,您将不得不学习如何通过 CUDA 深拷贝操作进行工作。 this answer 一步一步地走过。碰巧的是,您实际上并没有尝试在设备代码中取消引用该指针 - 您只是将结构从一个地方复制到另一个地方。因此,我们无需深入研究,即可让您显示的设备代码正常工作。

  • 段错误的近端原因是您没有在代码中的任何位置初始化 mom 结构成员,但您试图在此处取消引用它:

    std::cout<<*(paramresult[i].mom)<<"\t";
    

    在 C 或 C++ 中,如果您尝试取消引用尚未初始化的指针,则可能会发生不好的事情。我们可以通过注释掉那行代码来解决这个问题。我们还可以通过将只是数字指针值从设备代码中的weights 结构成员复制到mom 结构成员来“修复”它。但是我们不能直接在设备代码中使用这些指针,因为它们是上面指出的主机指针。

以下代码已解决上述第一项和第三项。它似乎对我来说运行正确。

$ cat t1529.cu
#include<iostream>
#include <stdio.h>

#define cudaCheckErrors(msg) \
    do { \
        cudaError_t __err = cudaGetLastError(); \
        if (__err != cudaSuccess) { \
            fprintf(stderr, "Fatal error: %s (%s at %s:%d)\n", \
                msg, cudaGetErrorString(__err), \
                __FILE__, __LINE__); \
            fprintf(stderr, "*** FAILED - ABORTING\n"); \
            exit(1); \
        } \
    } while (0)

struct MultiSGDKernelParam {
  int count;
  size_t sizes;
  float *weights;
  float *mom;
  float lrs;
};


__global__ void Launch(MultiSGDKernelParam *param, int N, MultiSGDKernelParam *result)
{
  for(int i=0; i<N; i++)
  {
     result[i] =param[i];
  }
}

MultiSGDKernelParam *fillStructure(float *temp, const int N)
{
    MultiSGDKernelParam *param;
        param = (MultiSGDKernelParam*) malloc( N * sizeof(MultiSGDKernelParam));
        for( int i=0; i< N ; i++)
        {
            param[i].count = i;
            param[i].sizes =  i*2;
            param[i].lrs =  param[i].sizes - i;
            param[i].weights = &temp[i];
        }

    std::cout<<"Inside the function"<<"\n";
        for(int i=0; i< N; i++)
        {
                std::cout<<param[i].sizes<<" ,"<<param[i].lrs<<"\t";
        }

    std::cout<<std::endl;
        for(int i =0 ; i<N;i++)
        {
          std::cout<<*(param[i].weights)<<"\t";

        }
        std::cout<<std::endl;
    MultiSGDKernelParam *d_param;
        cudaMalloc((void**)&d_param, N  * sizeof(MultiSGDKernelParam));
        cudaMemcpy(d_param,param,N  * sizeof(MultiSGDKernelParam),cudaMemcpyHostToDevice);

    return d_param;

}

MultiSGDKernelParam * fillFullStructure(float *tweight, float *tmom,  const int N )
{
  MultiSGDKernelParam *param = fillStructure( tweight, N );

 /* float *d_mom;

   cudaMalloc((void**)&d_mom,N*sizeof(float));
   cudaCheckErrors("cudaMalloc1 fail");
   cudaMemcpy(d_mom,tmom,N*sizeof(float), cudaMemcpyHostToDevice);
   cudaCheckErrors("cudaMemcpy1 fail");*/
   for( int i=0; i< N ; i++)
        {
          cudaMemcpy(&(param[i].mom),&(tmom[i]),sizeof(float), cudaMemcpyHostToDevice);
      cudaCheckErrors("cudaMempcpy2 fail");
        }

    std::cout<<"Momentum Values copied"<<"\n";
   /*cudaMemcpy(&(param->mom),tmom,N*sizeof(float), cudaMemcpyHostToDevice);
   cudaCheckErrors("cudaMempcpy1fail");*/
   return param;
}



int main()
{
    static const  int N =5;
    float tempweight [N], tempmom[N] ;
    for(int i=0; i< N; i++)
    {
            tempweight[i] = i*3 +1;
        tempmom[i] = i+3;
    }

    MultiSGDKernelParam *result;
    MultiSGDKernelParam *param = fillFullStructure( tempweight,tempmom, N );
    const unsigned blocks = 1;
    const unsigned threadsPerBlock = 1;
    cudaMalloc(&result, N  * sizeof(MultiSGDKernelParam));
    Launch<<<blocks,threadsPerBlock>>>(param, N, result);
    cudaDeviceSynchronize();
    MultiSGDKernelParam *paramresult;
    paramresult = (MultiSGDKernelParam*) malloc( N * sizeof(MultiSGDKernelParam));
    cudaMemcpy(paramresult,result, N * sizeof(MultiSGDKernelParam),cudaMemcpyDeviceToHost);
    std::cout<<"Inside Main"<<"\n";
    for(int i=0; i< N; i++)
        {
           std::cout<<paramresult[i].sizes<<" ,"<<paramresult[i].lrs<<"\t";
        }
    std::cout<<std::endl;
    for(int i =0 ; i<N;i++)
    {
          std::cout<<*(paramresult[i].weights)<<"\t";
        //  std::cout<<*(paramresult[i].mom)<<"\t";
    }
         std::cout<<std::endl;

    return 0;
}

$ nvcc -o t1529 t1529.cu
$ cuda-memcheck ./t1529
========= CUDA-MEMCHECK
Inside the function
0 ,0    2 ,1    4 ,2    6 ,3    8 ,4
1       4       7       10      13
Momentum Values copied
Inside Main
0 ,0    2 ,1    4 ,2    6 ,3    8 ,4
1       4       7       10      13
========= ERROR SUMMARY: 0 errors
$

如果您想在设备代码中实际使用weightsmom 结构成员(指针),则需要开始尝试了解CUDA 中的深拷贝操作。我已经为您提供了逐步说明该过程的链接,并附有一个工作示例。现在,您的代码中没有任何迹象表明您已经实现了任何这些,并且为您编写代码超出了我打算在这里回答的范围,因为您没有尝试过。

【讨论】:

  • 感谢您的宝贵回答。但是你提到我没有初始化妈妈的值。这发生在 side fillFullStructure 函数中,代码如下 cudaMemcpy(&(param[i].mom),&(tmom[i]),sizeof(float), cudaMemcpyHostToDevice);但是复制没有正确进行,这可能会导致段错误。我将参考您共享的线路并尝试更正错误。再次感谢。
  • 很好,那行代码也坏了,需要改成cudaMemcpy(&amp;(param[i].mom),&amp;tmom,sizeof(float *), cudaMemcpyHostToDevice);
猜你喜欢
  • 2017-08-27
  • 2013-09-20
  • 1970-01-01
  • 2012-03-07
  • 2011-08-24
  • 2013-03-25
  • 2014-08-30
  • 2023-03-14
  • 2018-03-13
相关资源
最近更新 更多