【问题标题】:CUDA - copy to array within array of ObjectsCUDA - 复制到对象数组中的数组
【发布时间】:2011-10-19 06:25:00
【问题描述】:

我有一个正在处理对象数组的 CUDA 应用程序;每个对象都有一个指向std::pair<int, double> 数组的指针。我正在尝试 cudaMemcpy 对象数组,然后 cudaMemcpy 对每个对象的数组,但是这给了我各种各样的悲伤。尝试复制到内部数组时崩溃;我不明白如何移动它...

#include <cuda.h>

#include <cuda_runtime.h>

#include <iostream>

using namespace std;

class Object
{
public:
    int id;
    float something;
    std::pair<int, float> *somePairs;
};

Object *objects;

void initObjects()
{
    objects = new Object[10];

    for( int idx = 0; idx < 10; idx++ )
    {
        objects[idx].id = idx;
        objects[idx].something = (float) idx;
    objects[idx].somePairs = new std::pair<int, float>[10];

        for ( int jdx = 10; jdx < 10; jdx++ )
        {
           objects[idx].somePairs[jdx] = std::pair<int, float>( jdx, (float) jdx );
        }

    }
}



void cudaMemcpyObjects()
{
     Object *devObjects;

     cudaMalloc( &devObjects, sizeof(Object) * 10 );
     cudaMemcpy( devObjects, objects, sizeof(Object) * 10, cudaMemcpyHostToDevice );

     for ( int idx = 0; idx < 10; idx++ )
     {
         size_t pairSetSize = sizeof(std::pair<int, float>) * 10;

         // CRASH HERE ... v
         cudaMalloc( &(devObjects[idx].somePairs), pairSetSize );
         cudaMemcpy( devObjects[idx].somePairs, objects[idx].somePairs,
                     sizeof( std::pair<int, float> ) * 10, cudaMemcpyHostToDevice );

     }


}


int main()
{
    initObjects();
    cudaMemcpyObjects();
    return 0;
}

【问题讨论】:

  • 这引出了一个问题:为什么? CUDA 代码不支持 C++ 标准库容器类。
  • 嗯,首先,您可以在 CUDA 代码中读取 STD 容器。您可以轻松引用 .first 和 .second 。尽管您可以将其替换为任何数组内数组,但也会出现同样的问题。
  • CUDA 标准库不包含任何 c++ 容器的定义,如果不进行大量修改,主机版本将无法编译。如果您愿意发布一个,我非常希望看到一个自包含的 repro 内核来演示这一点。
  • @talonmies - this: pastebin.com/62L0a13J - 一个特别无用的示例,但可以编译并运行。同样,我对您的评论的反驳是,一个 可以 读取 CUDA 中的标准容器。您不能从 CUDA 调用主机代码,因此诸如 vector.at(i) 之类的东西将不起作用。

标签: c++ cuda gpgpu


【解决方案1】:

我的 CUDA 体验还处于起步阶段,但我相信错误是这样的:

cudaMalloc 是一个 host 函数,它希望将指针写入 host 内存。但是,您正在向它传递 device 内存中的指针!

要解决这个问题,您应该首先创建设备指针并将它们填充到您的主机对象结构中,然后才将整个内容复制到设备上,并将各个对也复制到设备上。

示意图:

struct Bar;

struct Foo
{
  int tag;
  Bar * bp;
};

void setup()
{
  Foo * hFoo = new Foo[10];

  Foo * dFoo;
  cudaMalloc(dFoo, sizeof(Foo) * 10);

  for (size_t i = 0; i != 10; ++i)
  {
    Bar * dBar;
    cudaMalloc(&dbar, sizeof(Bar));

    Bar b;  // automatic temporary -- we never keep a host copy of this
    cudaMemcpy(dBar, &b, sizeof(Bar));

    hFoo[i].bp = dBar;    // this is already a device pointer!
  }

  cudaMemcpy(dFoo, hFoo, sizeof(Foo) * 10);
}

在返回时,不要忘记Foo::bp设备指针,你仍然需要一个一个复制回来!

只拥有一个可以一次性移动的自包含类可能会更容易,但这可能不实用,或者由于内存局部性的原因是不可取的。你必须谨慎对待这件事。如果成员只是一对,为什么不直接把这两个项目放在主类中呢?

【讨论】:

  • cudaMalloc 确实采用了设备指针。你对 cudaMallocHost 感到困惑吗?
  • 我没想到这会如此痛苦。我希望我缺少一些明显的东西。 (我的代码中的实际构造不仅仅是一个带有一对的结构,这只是一个显示问题的示例。)Kerrek,如果我为每个对象保留两个指针,一个用于主机,一个用于开发,您的解决方案可能会起作用...
  • 想想,我之前怎么没想到……? class foo { // 一些变量 float *data;浮动*设备数据; };
  • 类似的东西...您必须以一种或另一种方式在主机上创建所有内容,然后将所有内容放到设备上,然后再返回。任何手动分配都必须意识到这一点。或者,您可以尝试映射内存,这可能更容易(这就是您的cudaMallocHost 的来源)。
  • Kerrek SB 的方法是做到这一点的正确方法。将内部设备指针分配给外部(主机)结构的指针成员变量,然后将整个初始化的外部主机结构复制到外部设备结构。 CUDA 4.0 的 UVA 应该让这更简单——您可以直接访问主机内存并将您需要的内容复制到使用它的内核内部的设备中。
猜你喜欢
  • 2020-08-23
  • 2015-01-13
  • 2017-09-19
  • 1970-01-01
  • 2019-05-12
  • 2018-10-24
  • 1970-01-01
  • 2013-05-28
相关资源
最近更新 更多