在Nvidia GPU上,当我调用clEnqueueNDRange
时,程序会在继续之前等待它完成。更确切地说,我称之为等效的C ++绑定,CommandQueue::enqueueNDRange
,但这不应该有所作为。这只发生在Nvidia硬件(3 Tesla M2090s)远程;在我们的办公室工作站上使用AMD GPU,呼叫是无阻塞的,并立即返回。我没有测试的本地Nvidia硬件 - 我们曾经,而且我也记得类似的行为,但它有点模糊。
这使得跨多个GPU的工作更加困难。我已经尝试在新的C ++ 11规范中使用std::async
/ std::finish
为enqueueNDRange的每个调用启动一个新线程,但这似乎也不起作用 - 监视nvidia中的GPU使用情况-smi,我可以看到GPU 0上的内存使用率上升,然后它做了一些工作,然后GPU 0上的内存下降,GPU 1上的内存上升,一个做了一些工作,等等。我的gcc版本是4.7.0。
以下是我启动内核的方法,其中增量是所需的全局工作大小除以设备数量,四舍五入到所需本地工作大小的最接近倍数:
std::vector<cl::CommandQueue> queues;
/* Population of queues happens somewhere
cl::NDrange offset, increment, local;
std::vector<std::future<cl_int>> enqueueReturns;
int numDevices = queues.size();
/* Calculation of increment (local is gotten from the function parameters)*/
//Distribute the job among each of the devices in the context
for(int i = 0; i < numDevices; i++)
{
//Update the offset for the current device
offset = cl::NDRange(i*increment[0], i*increment[1], i*increment[2]);
//Start a new thread for each call to enqueueNDRangeKernel
enqueueReturns.push_back(std::async(
std::launch::async,
&cl::CommandQueue::enqueueNDRangeKernel,
&queues[i],
kernels[kernel],
offset,
increment,
local,
(const std::vector<cl::Event>*)NULL,
(cl::Event*)NULL));
//Without those last two casts, the program won't even compile
}
//Wait for all threads to join before returning
for(int i = 0; i < numDevices; i++)
{
execError = enqueueReturns[i].get();
if(execError != CL_SUCCESS)
std::cerr << "Informative error omitted due to length" << std::endl
}
内核肯定应该在调用std::async
时运行,因为我可以创建一个小的虚函数,在GDB中设置一个断点,并在调用std::async
时让它进入它。但是,如果我为enqueueNDRangeKernel创建一个包装器函数,在那里运行它,并在运行后放入一个print语句,我可以看到打印之间需要一些时间。
P.S。由于黑客等原因,Nvidia开发区已经失效,所以我无法在那里发布问题。
编辑:忘了提 - 我作为一个段传递给内核的缓冲区(我上面提到的那个似乎在GPU之间传递的缓冲区)被声明为使用CL_MEM_COPY_HOST_PTR。我一直在使用CL_READ_WRITE_BUFFER,效果相同。
答案 0 :(得分:2)
我给Nvidia的人发了电子邮件,实际上得到了相当公正的回应。 Nvidia SDK中的示例显示,您需要创建单独的每个设备:
此外,您必须为单独线程中的每个队列调用EnqueueNDRangeKernel。这不在SDK样本中,但是Nvidia家伙确认这些电话是封锁的。
完成所有这些后,我在多个GPU上实现了并发性。但是,仍然存在一些问题。 On to the next question...
答案 1 :(得分:0)
是的,你是对的。 AFAIK - nvidia实现具有同步“clEnqueueNDRange”。我在使用我的图书馆(Brahma)时也注意到了这一点。我不知道是否有解决方法或防止这种情况的方法,使用不同的实现(以及设备)保存。