Cuda 推力中的sort_by_键是阻塞调用吗?

Cuda 推力中的sort_by_键是阻塞调用吗?,cuda,gpgpu,thrust,Cuda,Gpgpu,Thrust,我反复将一系列内核排队: for 1..100: for 1..10000: // Enqueue GPU kernels Kernel 1 - update each element of array Kernel 2 - sort array Kernel 3 - operate on array end // run some CPU code output "Waiting for

我反复将一系列内核排队:

for 1..100:
    for 1..10000:
        // Enqueue GPU kernels
        Kernel 1 - update each element of array  
        Kernel 2 - sort array  
        Kernel 3 - operate on array  
    end
    // run some CPU code
    output "Waiting for GPU to finish"
    // copy from device to host
    cudaMemcpy ... D2H(array)
end
内核3的阶数是O(N^2),因此是迄今为止最慢的。对于内核2,我直接在设备上使用推力::按密钥排序:

thrust::device_ptr<unsigned int> key(dKey);
thrust::device_ptr<unsigned int> value(dValue);
thrust::sort_by_key(key,key+N,value);
推力::装置ptr键(dKey);
推力:装置的ptr值(D值);
推力::按_键对_排序(键,键+N,值);
这个对推力的调用似乎是阻塞的,因为CPU代码只有在内部循环完成后才能执行。我之所以看到这一点,是因为如果我删除对
sort\u by_key
的调用,主机代码(正确)会在内部循环完成之前输出“Waiting”字符串,而如果我运行排序,则不会输出

有没有一种方法可以异步调用<代码>推力::按\u键排序

首先考虑有一个内核启动队列,它只能容纳这么多未决的发射。一旦启动队列已满,其他任何类型的内核启动都会被阻塞。在空队列槽可用之前,主机线程将不会继续(超出这些启动请求)。我敢肯定,在达到10000次迭代之前,3次内核发布的10000次迭代将填满这个队列。因此,如果您按顺序启动30000个内核,那么任何类型的非平凡内核启动都会有一些延迟(我认为)。(但是,最终,当所有内核都被添加到队列中时,因为有些内核已经完成了,如果没有其他阻塞行为,那么在所有内核实际完成之前,您将看到“waiting…”消息。)

  • 推力::按键排序
    (大小约等于数据集大小)。每次使用时,都会通过
    cudamaloc
    操作在引擎盖下分配临时存储。此
    cudamaloc
    操作被阻塞。当从主机线程启动
    cudamaloc
    时,它会等待内核活动出现间隙,然后才能继续

  • 为了解决第2项,似乎至少有两种可能的方法:

  • 提供一个。根据此分配器的特性,您可能能够消除阻塞
    cudamaloc
    行为。(但见下文讨论)

  • 使用。这里的优点(在我看来,您的示例是不完整的)是,您可以执行一次分配(假设您知道整个循环迭代中最坏情况下的临时存储大小),并且无需在循环中执行临时内存分配


  • 据我所知,推力方法(1,上面)仍然会在每次迭代中有效地执行某种临时分配/空闲步骤,即使您提供了自定义分配器。如果您有一个设计良好的自定义分配器,那么这可能几乎是一个“无操作”。cub方法似乎有一个缺点,即需要知道最大大小(以便完全消除分配/空闲步骤的需要),但我认为对于推力自定义分配器也会有相同的要求。否则,如果您需要在某个时候分配更多内存,那么定制分配器实际上必须执行类似于
    cudamaloc
    的操作,这将给工作带来麻烦。

    嗨,罗伯特,谢谢!我不知道那个小熊。我现在可以预先分配临时存储。这甚至可能带来性能提升,尽管可能不会太多。队列大小将是我没有考虑的问题。我想知道是否有办法查询设备的最大队列大小……我不相信有办法查询队列大小(或可用插槽数)。据我所知,这不是一个出版数量。如果您愿意的话,编写一个程序来发现它是什么并不困难(至少大致如此)。但是,它可能会因设备而异,甚至可能因CUDA版本而异。