opencl - Nvidia 硬件上的 clEnqueueNDRange 阻塞? (还有多 GPU)

标签 opencl nvidia

在 Nvidia GPU 上,当我调用 clEnqueueNDRange 时,程序在继续之前等待它完成。更准确地说,我称它为等效的 C++ 绑定(bind),CommandQueue::enqueueNDRange ,但这应该没有什么区别。这只发生在远程 Nvidia 硬件(3 个 Tesla M2090s)上;在我们配备 AMD GPU 的办公室工作站上,调用是非阻塞的并立即返回。我没有要测试的本地 Nvidia 硬件 - 我们曾经有过,我记得当时也有类似的行为,但有点模糊。

这使得跨多个 GPU 分散工作变得更加困难。我尝试使用 std::async 为每次调用 enqueueNDRange 启动一个新线程/std::finish在新的 C++11 规范中,但这似乎也不起作用——监控 nvidia-smi 中的 GPU 使用情况,我可以看到 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 创建一个包装函数,在那里运行它,并在运行后放入打印语句,我可以看到打印之间需要一些时间。

附言由于黑客等原因,Nvidia 开发区已关闭,因此我无法在那里发布问题。

编辑: 忘记提及 - 我作为参数传递给内核的缓冲区(以及我在上面提到的似乎在 GPU 之间传递的缓冲区)声明为使用 CL_MEM_COPY_HOST_PTR。我一直在使用 CL_READ_WRITE_BUFFER,产生了同样的效果。

最佳答案

我给 Nvidia 的人发了邮件,实际上得到了相当公平的回复。 Nvidia SDK 中有一个示例显示,对于您需要单独创建的每个设备:

  • queues - 因此您可以代表每台设备并将订单排入队列
  • 缓冲区 - 您需要为每个数组传递一个缓冲区给设备,否则设备将绕过一个缓冲区,等待它可用并有效地序列化所有内容。
  • kernel - 我认为这是可选的,但它使指定参数变得容易得多。

此外,您必须在单独的线程中为每个队列调用 EnqueueNDRangeKernel。这不在 SDK 示例中,但 Nvidia 人员确认调用正在阻塞。

做完这一切,我实现了多GPU的并发。但是,仍然存在一些问题。 On to the next question...

关于opencl - Nvidia 硬件上的 clEnqueueNDRange 阻塞? (还有多 GPU),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11562543/

相关文章:

c - 指向 __local 结构中的 __global 内存的指针

gpu - 如何获取分配给多个GPU节点上的SLURM作业的GPU的ID?

compiler-errors - 如何从NVIDIA CG获得编译错误?

java - 动态地将Java线程转换为openCL内核

opencl - 在支持 OpenCL 的程序之间共享 GPU

opencl - 在 Ubuntu 上编译 OpenCL

opengl - glVertexPointer 的用途是什么?

python - Tensorflow导入错误: “cudart64_101.dll” not found (Windows 10)

opencl - clCreateSubBuffer 未找到 oO