鉴于此代码:
void foo(cv::gpu::GpuMat const &src, cv::gpu::GpuMat *dst[], cv::Size const dst_size[], size_t numImages)
{
cudaStream_t streams[numImages];
for (size_t image = 0; image < numImages; ++image)
{
cudaStreamCreateWithFlags(&streams[image], cudaStreamNonBlocking);
dim3 Threads(32, 16);
dim3 Blocks((dst_size[image].width + Threads.x - 1)/Threads.x,
(dst_size[image].height + Threads.y - 1)/Threads.y);
myKernel<<<Blocks, Threads, 0, streams[image]>>>(src, dst[image], dst_size[image]);
}
for (size_t image = 0; image < numImages; ++image)
{
cudaStreamSynchronize(streams[image]);
cudaStreamDestroy(streams[image]);
}
}
查看nvvp
的输出,我看到几乎完美的串行执行,即使第一个流是一个漫长的过程,其他流应该能够重叠。
请注意,我的内核使用了30个寄存器,并且所有寄存器都报告了&#34;已实现占用&#34;大约0.87。对于最小的图像,网格大小为[10,15,1]和块大小[32,16,1]。
答案 0 :(得分:1)
CUDA编程指南(link)中给出了描述并发内核执行限制的条件,但其中的要点是,只有当GPU足够时,GPU才可能从不同的流中运行多个内核这样做的资源。
在您的使用案例中,您已经说过您正在运行多个内核,每个内核包含150个512个线程的块。您的GPU有12个SMM(我认为),并且每个SMM可以同时运行最多 4个块(4 * 512 = 2048个线程,这是SMM限制)。因此,您的GPU最多只能同时运行4 * 12 = 48个块。当多个150个块的启动位于命令管道中时,似乎很少(甚至没有)并发内核执行的机会。
如果通过减小块大小来增加内核的调度粒度,那么可能能够鼓励内核执行重叠。较小的块比较大的块更可能找到可用资源和调度槽。同样,减少每个内核启动的总块数(可能通过增加每个线程的并行工作)可能也有助于增加多个内核重叠或并发执行的可能性。