2012-07-19 39 views
2

在Nvidia GPU上,当我拨打clEnqueueNDRange时,程序会在继续之前等待它完成。更确切地说,我打电话给它的等效C++绑定,CommandQueue::enqueueNDRange,但这不应该有所作为。这只发生在Nvidia硬件(3 Tesla M2090s)上;在我们配备AMD GPU的办公室工作站上,呼叫不受阻碍,并立即返回。我没有本地的Nvidia硬件来测试 - 我们曾经这样做过,而且我也记得类似的行为,但它有点朦胧。clEnqueueNDRange在Nvidia硬件上阻塞? (也是多GPU)

这使得难以在多个GPU之间传播工作。我已经尝试在新的C++ 11规范中使用std::async/std::finish来启动一个新线程,以便每次调用enqueueNDRange,但这似乎并不奏效 - 监控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创建一个包装函数,请在此处运行它,然后在运行后放入一个打印语句,我可以看到在打印之间需要一些时间。

P.S.由于黑客等原因,Nvidia开发区已经关闭,所以我无法在那里发布问题。

编辑:忘了提 - 那我传递给内核作为argment(和一个我提到,上面,这似乎让GPU之间传递)被声明为使用CL_MEM_COPY_HOST_PTR的缓冲区。我一直在使用CL_READ_WRITE_BUFFER,效果相同。

回答

2

我给Nvidia们发了封电子邮件,实际上得到了相当公平的答复。有一个在Nvidia的SDK,显示了样本,每个设备需要创建单独的:

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

此外,你必须为独立线程中的每个队列调用EnqueueNDRangeKernel。这不在SDK示例中,但Nvidia家伙确认这些通话被阻止。

做完所有这些之后,我在多个GPU上实现了并发。但是,仍然存在一些问题。 On to the next question...

0

是的,你是对的。 AFAIK - nvidia的实现有一个同步的“clEnqueueNDRange”。我在使用我的图书馆(梵天)时也注意到了这一点。我不知道是否有解决方法或防止这种方法,除了使用不同的实现(并因此设备)。

+0

那么,这是否意味着clEnqueueNDRange只能在任何给定的上下文中一次调用一次?这似乎是这种情况,正如我对'std :: async'的实验所暗示的那样。 编辑:或者,而不是一次调用一次,一次执行一个。 – Chaosed0 2012-07-19 14:19:07

+0

从我的实验来看,是的。每当我想要做更复杂的事时,我都会使用AMD(或Intel)实现。但是,您可以创建两个上下文,每个上下文都有一个设备,对吗? – Ani 2012-07-19 14:20:50

+0

井dangit。我的设置的问题是我需要此代码在多GPU设置上运行,并且我已经访问的两个GPU群集都有Nvidia卡。如果没有解决方法,那么我有点死在水里。在论坛不通的情况下向Nvidia的支持发送电子邮件是否值得? arghedit:是的,我想我可以尝试单独的上下文。 – Chaosed0 2012-07-19 14:22:10

相关问题