OpenCL:如何在上下文中选择GPU

OpenCL:如何在上下文中选择GPU,opencl,Opencl,我已从多个GPU设备中选择了我的上下文,如下所示: type = platforms[0].getDevices(CL_DEVICE_TYPE_GPU, &devices); if(type == CL_SUCCESS) { //Create context and access device names cl::Context ctx_(devices); context = ctx_; gpuDevices = context.getInfo<C

我已从多个GPU设备中选择了我的上下文,如下所示:

type = platforms[0].getDevices(CL_DEVICE_TYPE_GPU, &devices);
if(type == CL_SUCCESS)
{
    //Create context and access device names
    cl::Context ctx_(devices);
    context = ctx_;
    gpuDevices = context.getInfo<CL_CONTEXT_DEVICES>();
    for(i=0; i<gpuDevices.size(); i++) {
        deviceName = gpuDevices[i].getInfo<CL_DEVICE_NAME>();
        queues.emplace_back(cl::CommandQueue(context, gpuDevices[i], CL_QUEUE_PROFILING_ENABLE));
        op::log("Adding " + deviceName + " to queue");
    }
}
else if(type == CL_INVALID_DEVICE_TYPE || type == CL_DEVICE_NOT_FOUND)
{
    throw std::runtime_error("Error: GPU Invalid Device or Device not found");
}
break;

正如您所看到的,它只在1个上下文中使用,我无法选择我的GPU。当您为一个上下文创建一个缓冲区(在多个设备之间共享)时,缓冲区在这些设备之间“共享”,因此您可以使用相同的
cl\u mem
对象在这两个设备上执行命令。是否在两个设备上实际分配了用于保存此缓冲区的内存是由实现定义的。OpenCL驱动程序可能会推迟实际分配,直到在特定设备上执行的命令需要缓冲区为止,通常它足够聪明,可以做到这一点,但这实际上取决于硬件和实现细节

基本上,您有两种选择:

  • 查看OpenCL供应商文档,了解运行时如何为共享上下文执行内存分配
  • 为每个设备创建一个单独的
    cl::Context

  • 即使在只有一个设备的上下文中,缓冲区对象也可能同时驻留在设备和主机上。如果使用
    clEnqueueWriteBuffer
    填充缓冲区,这将在特定命令队列上发生,因此与特定设备关联。很显然,在这种情况下,大多数实现将在与队列对应的设备上分配内存,并使用其DMA引擎填充缓冲区

    但是,在OpenCL中没有比这更低级别的控件


    因此,如果您在不同设备的不同队列上使用相同的缓冲区,这取决于访问模式和实现的编写方式,可能会有多个副本四处浮动,或者实现会不断移动内存。分析将告诉您使用单独的上下文还是共享上下文更好。

    命令队列只服务于1个gpu。当您将“读/写缓冲区”排入其中一个队列时,它们会在该命令队列的gpu上执行操作。这意味着您需要2个命令队列。是的,但当我创建一个新的cl::Buffer时,它会被哪个gpu复制,toBuffers可以在其上下文中的任何地方移动。你决定他们怎么做。有时甚至是含蓄的。一旦创建了缓冲区写入命令,就可以直接发出该命令,以确保在这些设备上对其进行更新。最简单的方法是每个设备有一个上下文。但这意味着它们只能通过RAM或迁移命令进行通信。在整个pc上只使用一个上下文可以为您优化事情,这使得预测什么在哪里变得更加困难。实际上,在您真正使用它之前,它甚至可能是一个懒惰的分配。它甚至可以在RAM上有一个镜像,以加快复制速度。但您可以尝试使用CL_MEM_HOST_NO_ACCESS标志,以确保它不存在于RAM上。
    Buffer(
            const Context& context,
            cl_mem_flags flags,
            ::size_t size,
            void* host_ptr = NULL,
            cl_int* err = NULL)