1

鉴于此代码:

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 个寄存器,并且都报告了大约 0.87 的“Achieved Occupancy”。对于最小的图像,网格大小为 [10,15,1],块大小为 [32, 16,1]。

4

1 回答 1

2

CUDA 编程指南(链接)中给出了描述并发内核执行限制的条件,但要点是,只有当您的 GPU 有足够的资源来执行此操作时,您的 GPU 才可能从不同的流中运行多个内核。

在您的用例中,您说您正在运行内核的多次启动,每个内核有 150 个块,每个块有 512 个线程。你的 GPU 有 12 个 SMM(我认为),每个 SMM最多可以有4 个块同时运行(4 * 512 = 2048 个线程,这是 SMM 的限制)。所以你的 GPU 最多只能同时运行 4 * 12 = 48 个块。当在命令管道中多次启动 150 个块时,并发内核执行的机会似乎很小(甚至可能没有)。

如果您通过减小块大小来增加内核的调度粒度,您可能会鼓励内核执行重叠。较小的块比较大的块更有可能找到可用资源和调度时隙。同样,减少每次内核启动的总块数(可能通过增加每个线程的并行工作)也可能有助于增加多个内核重叠或并发执行的可能性。

于 2016-01-18T08:30:39.780 回答