我想知道系统端cl :: Buffer对象如何在多设备上下文中实例化。
假设我有一个OCL环境类,它从cl :: Platform生成ONE cl :: Context:
this->ocl_context = cl::Context(CL_DEVICE_TYPE_GPU, con_prop);
然后,相应的一组设备:
this->ocl_devices = this->ocl_context.getInfo<CL_CONTEXT_DEVICES>();
我为EACH设备生成一个cl :: CommandQueue对象和一组cl :: Kernel。
假设我有4个相同类型的GPU。现在我在ocl_devices中有4x 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);
然后在INSIDE EACH CLASS中,我都实例化了:
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,总是为每个需要的内核:: setArg传递&amp; shared_buffer。我很难绕过去做什么。
答案 0 :(得分:2)
当您拥有包含多个设备的上下文时,您在该上下文中创建的任何缓冲区都可见到其所有设备。这意味着上下文中的任何设备都可以从上下文中的任何缓冲区读取,并且OpenCL实现负责确保数据在需要时实际移动到正确的设备。如果多个设备同时尝试并访问同一缓冲区,应该会发生一些灰色区域,但无论如何通常都会避免这种行为。
尽管所有设备都可以看到所有缓冲区,但这并不一定意味着它们将在所有设备上分配。我使用的所有OpenCL实现都使用“首先使用分配”策略,只有当设备需要缓冲区才会在设备上分配缓冲区。因此,在您的特定情况下,每个设备最终应该有一个缓冲区,只要每个缓冲区仅由一个设备使用即可。
理论上,OpenCL实现可能会在所有设备上预先分配所有缓冲区,以防万一它们需要,但我不希望这种情况在现实中发生(我当然也从未见过这种情况)。如果您在具有GPU分析器的平台上运行,您通常可以使用分析器来查看缓冲区分配和数据移动实际发生的时间和位置,以说服自己系统没有做任何不合需要的事情。