【问题标题】:OpenCL Buffer Instantiation in a Multi Device Environment多设备环境中的 OpenCL 缓冲区实例化
【发布时间】:2014-03-13 04:31:52
【问题描述】:

我想知道系统端 cl::Buffer 对象如何在多设备上下文中实例化。

假设我有一个 OCL 环境类,它从 cl::Platform 生成一个 cl::Context:

this->ocl_context = cl::Context(CL_DEVICE_TYPE_GPU, con_prop);

然后,对应的一组设备:

this->ocl_devices = this->ocl_context.getInfo<CL_CONTEXT_DEVICES>();

我为每个设备生成一个 cl::CommandQueue 对象和一组 cl::Kernel(s)。

假设我有 4 个相同类型的 GPU。现在我在 ocl_devices 中有 4 个 cl::Device 对象。

现在,当我有第二个处理程序类来管理每个设备上的计算时会发生什么:

oclHandler h1(cl::Context* c, cl::CommandQueue  cq1, std::vector<cl::Kernel*> k1);
...
oclHandler h2(cl::Context* c, cl::CommandQueue  cq4, std::vector<cl::Kernel*> k4);

然后在每个类中,我都实例化:

oclHandler::classMemberFunction(
...
  this->buffer =
    cl::Buffer(
      *(this->ocl_context),
      CL_MEM_READ_WRITE,
      mem_size,
      NULL,
      NULL
    );

...
)

然后写到

oclHandler::classMemberFunction(
...
this->ocl_cq->enqueueWriteBuffer(
      this->buffer,
      CL_FALSE,
      static_cast<unsigned int>(0),
      mem_size,
      ptr,
      NULL,
      NULL
    );
...
this->ocl_cq.finish();
...
)

每个缓冲区。有人担心,因为实例化是针对 cl::context,而不是绑定到特定设备,所以每个设备上可能有四倍的内存地址分配。我无法确定“在设备上,此缓冲区从 0xXXXXXXXXXXXXXXXX 运行 N 个字节”的操作何时发生。

应该为每个设备实例化一个上下文吗?这似乎不自然,因为我必须实例化一个上下文。看看有多少个设备,然后再实例化 d-1 多个上下文....似乎效率低下。我担心的是限制可用内存设备方面。我正在对大量数据集进行计算,我可能会使用每张卡上所有可用的 6GB。

谢谢。

编辑:有没有办法在不使用命令队列的情况下实例化缓冲区并异步填充它?就像假设我有 4 台设备和一个充满静态只读数据的缓冲区主机端。假设缓冲区大小为 500MB。如果我只想使用 clCreateBuffer,与

shared_buffer = new
cl::Buffer(
  this->ocl_context,
  CL_MEM_READ_ONLY | CL_MEM_ALLOC_HOST_PTR | CL_MEM_COPY_HOST_PTR,
  total_mem_size,
  ptr
  NULL
);

这将启动阻塞写入,在将所有 ptr 的内容复制到新分配的内存之前,我无法在主机端执行任何操作。我有一个多线程设备管理系统,我为每个设备创建了一个 cl::CommandQueue,总是为每个所需的 kernel::setArg 传递 &shared_buffer。我很难思考该怎么做。

【问题讨论】:

    标签: c++ opencl gpu


    【解决方案1】:

    当您有一个包含多个设备的上下文时,您在该上下文中创建的任何缓冲区都对它的所有设备可见。这意味着上下文中的任何设备都可以从上下文中的任何缓冲区读取数据,并且 OpenCL 实现负责确保数据在需要时实际移动到正确的设备。如果多个设备同时尝试访问同一个缓冲区,将会出现一些灰色区域,但这种行为通常是可以避免的。

    虽然所有缓冲区对所有设备都是可见的,但这并不一定意味着它们将被分配到所有设备上。我使用过的所有 OpenCL 实现都使用“首次使用时分配”策略,即只有在设备需要时才在设备上分配缓冲区。因此,在您的特定情况下,您应该最终为每个设备提供一个缓冲区,只要每个缓冲区仅由一个设备使用。

    理论上,OpenCL 实现可能会预先分配所有设备上的所有缓冲区以防万一,但我不希望这会在现实中发生(而且我当然从未见过这种情况发生)。如果您在具有可用 GPU 分析器的平台上运行,您通常可以使用分析器查看缓冲区分配和数据移动实际发生的时间和地点,以说服自己系统没有做任何不希望的事情。

    【讨论】:

    • CodeXL 会跟踪吗?我一直想使用它,但我从来没有使用过它。此外,我对 *ptr 和阻塞实际 cl::Buffer 构造函数的写入参数究竟做了什么感到困惑?在那种情况下,它会复制到所有设备吗?谢谢。
    • 我不确定 CodeXL 到底显示了什么,但任何半体面的分析器都应该显示主机和设备(以及设备到设备)之间的内存传输,所以这应该足以看到发生了什么.
    • 我不知道你指的是哪个 Buffer 构造函数。使用主机指针和 CL_MEM_COPY_HOST_PTR 创建缓冲区将导致数据被复制到 context,这可能只是驱动程序在主机上其他地方分配的缓冲区。请注意,全局内存被定义为在上下文中,而不是在设备上;规范声明数据可以在设备上缓存,但从概念的角度来看,这并不是它实际存在的地方。
    • 诚然,我对驱动程序的内存管理有点模糊。你知道我可以从哪里获得更多相关信息吗?
    • 我之前的评论有点不准确。全局内存确实在内核执行期间存在于设备上,但内存对象本身处于上下文级别,可以在设备外部。要掌握这些内容,最好的办法是阅读 OpenCL 规范的内存模型部分(1.2 规范的第 3.3 节,附录 A 专门处理共享对象)。运行时管理和移动内存的确切方式是特定于供应商的,因此很难获得有关如何完成此操作的任何真实细节。
    猜你喜欢
    • 2017-07-29
    • 1970-01-01
    • 2015-08-13
    • 1970-01-01
    • 2012-07-23
    • 2019-05-05
    • 2013-06-19
    • 1970-01-01
    • 2016-12-03
    相关资源
    最近更新 更多