Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用主机上CUDA内核中动态分配的数据_C++_Cuda_Dynamic Memory Allocation_Memcpy - Fatal编程技术网

C++ 使用主机上CUDA内核中动态分配的数据

C++ 使用主机上CUDA内核中动态分配的数据,c++,cuda,dynamic-memory-allocation,memcpy,C++,Cuda,Dynamic Memory Allocation,Memcpy,我正在尝试在设备上构建一个容器类来管理一些内存。 这个内存是动态分配的,并在内核中的对象构造期间填充。 根据在内核中使用一个简单的新[]可以完成的文档(在Visual Studio 2012中使用CUDA 8.0和compute cabability 5.0)。 之后,我希望访问主机代码中容器内的数据(例如,用于测试所有值是否正确) DeviceContainer类的最低版本如下所示: class DeviceContainer { public: __device__ DeviceCo

我正在尝试在设备上构建一个容器类来管理一些内存。 这个内存是动态分配的,并在内核中的对象构造期间填充。 根据在内核中使用一个简单的新[]可以完成的文档(在Visual Studio 2012中使用CUDA 8.0和compute cabability 5.0)。 之后,我希望访问主机代码中容器内的数据(例如,用于测试所有值是否正确)

DeviceContainer
类的最低版本如下所示:

class DeviceContainer 
{
public:
   __device__ DeviceContainer(unsigned int size);
   __host__ __device__ ~DeviceContainer();

   __host__ __device__ DeviceContainer(const DeviceContainer & other);
   __host__ __device__ DeviceContainer & operator=(const DeviceContainer & other);

   __host__ __device__ unsigned int getSize() const { return m_sizeData; }
   __device__ int * getDataDevice() const { return mp_dev_data; }
   __host__ int* getDataHost() const;

private:
   int * mp_dev_data;
   unsigned int m_sizeData;
};


__device__ DeviceContainer::DeviceContainer(unsigned int size) :
      m_sizeData(size), mp_dev_data(nullptr) 
{
   mp_dev_data = new int[m_sizeData];

   for(unsigned int i = 0; i < m_sizeData; ++i) {
      mp_dev_data[i] = i;
   }
}


__host__ __device__ DeviceContainer::DeviceContainer(const DeviceContainer & other) : 
  m_sizeData(other.m_sizeData)
{
#ifndef __CUDA_ARCH__
   cudaSafeCall( cudaMalloc((void**)&mp_dev_data, m_sizeData * sizeof(int)) );
   cudaSafeCall( cudaMemcpy(mp_dev_data, other.mp_dev_data, m_sizeData * sizeof(int), cudaMemcpyDeviceToDevice) );
#else
   mp_dev_data = new int[m_sizeData];
   memcpy(mp_dev_data, other.mp_dev_data, m_sizeData * sizeof(int));
#endif
}


__host__ __device__ DeviceContainer::~DeviceContainer()
{
#ifndef __CUDA_ARCH__
   cudaSafeCall( cudaFree(mp_dev_data) );
#else
   delete[] mp_dev_data;
#endif
   mp_dev_data = nullptr;
}


__host__ __device__ DeviceContainer & DeviceContainer::operator=(const DeviceContainer & other)
{
   m_sizeData = other.m_sizeData;

 #ifndef __CUDA_ARCH__
   cudaSafeCall( cudaMalloc((void**)&mp_dev_data, m_sizeData * sizeof(int)) );
   cudaSafeCall( cudaMemcpy(mp_dev_data, other.mp_dev_data, m_sizeData * sizeof(int), cudaMemcpyDeviceToDevice) );
#else
   mp_dev_data = new int[m_sizeData];
   memcpy(mp_dev_data, other.mp_dev_data, m_sizeData * sizeof(int));
#endif

   return *this;
}


__host__ int* DeviceContainer::getDataHost() const
{
   int * pDataHost = new int[m_sizeData];
   cudaSafeCall( cudaMemcpy(pDataHost, mp_dev_data, m_sizeData * sizeof(int), cudaMemcpyDeviceToHost) );
   return pDataHost;
}
范围内的一维网格中的每个线程都创建一个容器对象

然后,main函数为设备和主机上的容器(本例中为90000)分配数组,调用内核并尝试使用对象:

void main()
{
   const unsigned int numContainer = 90000;
   const unsigned int containerSize = 5;

   DeviceContainer * pDevContainer;
   cudaSafeCall( cudaMalloc((void**)&pDevContainer, numContainer * sizeof(DeviceContainer)) );

   dim3 blockSize(1024, 1, 1);
   dim3 gridSize((numContainer + blockSize.x - 1)/blockSize.x , 1, 1);

   createContainer<<<gridSize, blockSize>>>(pDevContainer, numContainer, containerSize);
   cudaCheckError();

   DeviceContainer * pHostContainer = (DeviceContainer *)malloc(numContainer * sizeof(DeviceContainer)); 
   cudaSafeCall( cudaMemcpy(pHostContainer, pDevContainer, numContainer * sizeof(DeviceContainer), cudaMemcpyDeviceToHost) );

   for(unsigned int i = 0; i < numContainer; ++i)
   {
      const DeviceContainer & dc = pHostContainer[i];

      int * pData = dc.getDataHost();
      for(unsigned int j = 0; j < dc.getSize(); ++j)
      {
         std::cout << pData[j];
      }
      std::cout << std::endl;
      delete[] pData;
   }

   free(pHostContainer);
   cudaSafeCall( cudaFree(pDevContainer) );
}
我对此代码有3个问题:

  • 如果按照这里所示执行,我会收到内核的“未指定的启动失败”。Nsight调试器在
    mp_dev_data=newint[m_sizeData]行上停止我(在构造函数或赋值运算符中),并报告全局内存上的多个访问冲突。冲突的数量在4到11之间是随机的,它们发生在非连续线程中,但总是在网格的上端附近(方框85和86)

  • 如果我将
    numContainer
    减少到10,内核将平稳运行,但是
    getDataHost()
    中的
    cudaMamcpy
    会失败,并出现无效参数错误-即使
    mp_dev_data
    不是0。(我怀疑分配有问题,内存已被另一个对象删除。)

  • 尽管我想知道如何通过适当的内存管理正确实现
    DeviceContainer
    ,但在我的情况下,它也足以使其不可复制和不可分配。但是,我不知道如何正确地填充内核中的容器数组。也许像

    设备容器dc(5);
    memcpy(&pContainer[offset],&dc,sizeof(DeviceContainer))

    这将导致在析构函数中删除
    mp\u dev\u数据时出现问题。我需要手动管理内存删除,这感觉相当脏

  • 我还尝试在内核代码中使用
    malloc
    free
    ,而不是
    new
    delete
    ,但结果是一样的

    很抱歉,我没能用较短的方式提出我的问题

    TL;DR:如何实现一个在内核中动态分配内存并且也可以在主机代码中使用的类?如何使用无法复制或分配的对象初始化内核中的数组


    感谢您的帮助。谢谢。

    显然,答案是:我想做的或多或少是不可能的。 内核中用
    new
    malloc
    分配的内存不是放在全局内存中,而是放在主机无法访问的特殊堆内存中

    访问主机上所有内存的唯一选项是,首先在全局内存中分配一个数组,该数组足够大,可以容纳堆上的所有元素,然后编写一个内核,将堆中的所有元素复制到全局内存中


    访问冲突是由有限的堆大小引起的(可以通过
    cudaDeviceSetLimit(cudaLimitMallocHeapSize,size\u t size)更改)

    显然,答案是:我试图做的或多或少是不可能的。 内核中用
    new
    malloc
    分配的内存不是放在全局内存中,而是放在主机无法访问的特殊堆内存中

    访问主机上所有内存的唯一选项是,首先在全局内存中分配一个数组,该数组足够大,可以容纳堆上的所有元素,然后编写一个内核,将堆中的所有元素复制到全局内存中

    访问冲突是由有限的堆大小引起的(可通过
    cudaDeviceSetLimit(cudaLimitMallocHeapSize,size\u t size)
    更改)

    void main()
    {
       const unsigned int numContainer = 90000;
       const unsigned int containerSize = 5;
    
       DeviceContainer * pDevContainer;
       cudaSafeCall( cudaMalloc((void**)&pDevContainer, numContainer * sizeof(DeviceContainer)) );
    
       dim3 blockSize(1024, 1, 1);
       dim3 gridSize((numContainer + blockSize.x - 1)/blockSize.x , 1, 1);
    
       createContainer<<<gridSize, blockSize>>>(pDevContainer, numContainer, containerSize);
       cudaCheckError();
    
       DeviceContainer * pHostContainer = (DeviceContainer *)malloc(numContainer * sizeof(DeviceContainer)); 
       cudaSafeCall( cudaMemcpy(pHostContainer, pDevContainer, numContainer * sizeof(DeviceContainer), cudaMemcpyDeviceToHost) );
    
       for(unsigned int i = 0; i < numContainer; ++i)
       {
          const DeviceContainer & dc = pHostContainer[i];
    
          int * pData = dc.getDataHost();
          for(unsigned int j = 0; j < dc.getSize(); ++j)
          {
             std::cout << pData[j];
          }
          std::cout << std::endl;
          delete[] pData;
       }
    
       free(pHostContainer);
       cudaSafeCall( cudaFree(pDevContainer) );
    }
    
    #define cudaSafeCall(error) __cudaSafeCall(error, __FILE__, __LINE__)
    #define cudaCheckError()    __cudaCheckError(__FILE__, __LINE__)
    
    inline void __cudaSafeCall(cudaError error, const char *file, const int line)
    {
       if (error != cudaSuccess)
       {
          std::cerr << "cudaSafeCall() returned:" << std::endl;
          std::cerr << "\tFile: " << file << ",\nLine: " << line << " - CudaError " << error << ":" << std::endl;
          std::cerr << "\t" << cudaGetErrorString(error) << std::endl;
    
          system("PAUSE");
          exit( -1 );
       }
    }
    
    
    inline void __cudaCheckError(const char *file, const int line)
    {
       cudaError error = cudaDeviceSynchronize();
       if (error != cudaSuccess)
       {
          std::cerr << "cudaCheckError() returned:" << std::endl;
          std::cerr << "\tFile: " << file << ",\tLine: " << line << " - CudaError " << error << ":" << std::endl;
          std::cerr << "\t" << cudaGetErrorString(error) << std::endl;
    
          system("PAUSE");
          exit( -1 );
       }
    }