【问题标题】:Improving asynchronous execution in CUDA改进 CUDA 中的异步执行
【发布时间】:2013-04-19 06:19:10
【问题描述】:

我目前正在编写一个程序,该程序使用 CUDA API 在 GPU 上执行大型模拟。为了提高性能,我尝试同时运行我的内核,然后再次将结果异步复制到主机内存中。代码大致如下:

#define NSTREAMS   8
#define BLOCKDIMX  16
#define BLOCKDIMY  16

void domainUpdate(float* domain_cpu,       // pointer to domain on host
                  float* domain_gpu,       // pointer to domain on device
                  const unsigned int dimX,
                  const unsigned int dimY,
                  const unsigned int dimZ)
{
    dim3 blocks((dimX + BLOCKDIMX - 1) / BLOCKDIMX, (dimY + BLOCKDIMY - 1) / BLOCKDIMY);
    dim3 threads(BLOCKDIMX, BLOCKDIMY);

    for (unsigned int ii = 0; ii < NSTREAMS; ++ii) {

        updateDomain3D<<<blocks,threads, 0, streams[ii]>>>(domain_gpu,
                                                           dimX, 0,  dimX - 1, // dimX, minX, maxX
                                                           dimY, 0,  dimY - 1, // dimY, minY, maxY
                                                           dimZ, dimZ * ii / NSTREAMS,  dimZ * (ii + 1) / NSTREAMS - 1); // dimZ, minZ, maxZ

        unsigned int offset = dimX * dimY * dimZ * ii / NSTREAMS;
        cudaMemcpyAsync(domain_cpu + offset ,
                        domain_gpu+ offset ,
                        sizeof(float) * dimX * dimY * dimZ / NSTREAMS,
                        cudaMemcpyDeviceToHost, streams[ii]);
    }

    cudaDeviceSynchronize();
}

总而言之,它只是一个简单的 for 循环,循环所有流(本例中为 8 个)并划分工作。这实际上是一个更快的交易(高达 30% 的性能提升),尽管可能比我希望的要少。我在 Nvidia 的 Compute Visual Profiler 中分析了一个典型的循环,执行如下:

从图中可以看出,内核确实重叠,但同时运行的内核不会超过两个。我对不同数量的流和不同大小的模拟域尝试了相同的操作,但情况总是如此。

所以我的问题是:有没有办法鼓励/强制 GPU 调度程序同时运行两个以上的东西?或者这是依赖于无法在代码中表示的 GPU 设备的限制?

我的系统规格是:64 位 Windows 7,以及 GeForce GTX 670 显卡(即 Kepler 架构,计算能力 3.0)。

【问题讨论】:

    标签: c++ cuda gpu gpgpu


    【解决方案1】:

    仅当 GPU 有剩余资源可运行第二个内核时,内核才会重叠。 GPU 完全加载后,并行运行更多内核没有任何好处,因此驱动程序不会这样做。

    【讨论】:

    • 但是即使内核非常小,比如很多块,同时运行的内核也不会超过 2 个。所以 GPU 的物理尺寸不可能是全部,不是吗?
    • 是的,可以。什么是“小内核”?多少块?每个块有多少个线程?他们使用共享内存吗?注册?除非您分析了内核的资源利用率,否则您将不知道可以运行多少。 Windows(当 GPU 处于 WDDM 模式时)也可以通过批处理 GPU 活动来干扰并发性。 GPU 不限于同时运行两个东西。
    • 这是一个很好的观点,我并没有完全考虑所有共享内存和寄存器的要求,我不太明白这会在多大程度上影响性能。我尝试过的“小”内核是例如 8x8 块和 16x16 线程。其中,我想说,理论上更多的负载应该适合 GPU。它每个线程使用 33 个寄存器,每个块大约 2 kB 的共享内存。很多吗?
    • 使用占用计算器找出可以在一个多处理器上同时运行的块数。如果您的内核是 6 个块/SMX,因此 GTX 670 的 7 个 SMX 可以同时运行 42 个块。对于 64 个块的网格,第一波并发块将留下 22 个块在第二波中处理,如果第二次启动相同的内核(但不足以进行第三次启动),则为另外 20 个块留出空间。完美地解释了分析器的发现。
    • 感谢您的清晰解释,现在更有意义了!
    猜你喜欢
    • 2014-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-05
    • 1970-01-01
    • 2017-12-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多