C++ 多设备环境中的OpenCL缓冲区实例化

C++ 多设备环境中的OpenCL缓冲区实例化,c++,opencl,gpu,C++,Opencl,Gpu,我想知道系统端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>(); 然后,写信给 oclHa

我想知道系统端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>();
然后,写信给

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

这将开始一个阻塞写入,在主机端我不能做任何事情,直到所有ptr的内容都复制到新分配的内存中。我有一个多线程设备管理系统,我为每个设备创建了一个cl::CommandQueue,总是为每个kernel::setArg所需的内核传递&shared_缓冲区。我很难思考该做什么。

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

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


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

CodeXL是否跟踪这一点?我一直想用它,只是一直没时间用。此外,我还不清楚*ptr和实际cl::Buffer构造函数的阻塞写入参数到底是做什么的?在这种情况下,它会复制到所有设备吗??谢谢。我不确定CodeXL到底显示了什么,但任何一个半正常的分析器都应该显示主机和设备(以及设备到设备)之间的内存传输,这样就足以看到发生了什么。我不知道你指的是哪个缓冲区构造函数。使用主机指针和CL_MEM_COPY_host_PTR创建缓冲区将导致数据被复制到上下文中,而上下文可能只是驱动程序在主机上其他位置分配的缓冲区。注意,全局内存定义为在上下文中,而不是在设备上;该规范规定数据可以缓存在设备上,但从概念上讲,数据实际上并不存在于设备上。无可否认,我对驱动程序的内存管理有点模糊。你知道我在哪里可以得到更多的信息吗?我之前的评论有点不准确。在内核执行期间,全局内存确实存在于设备上,但内存对象本身处于上下文级别,可以在设备外部。要掌握这些东西,最好的办法是阅读OpenCL规范的内存模型部分(1.2规范的第3.3节,附录a专门处理共享对象)。运行时如何管理和移动内存是特定于供应商的,因此很难获得关于如何实现这一点的任何真正细节。
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();
...
)
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
);