当 运行 Numba 代码在 CUDA GPU 上时,我注意到我的 CPU 核心之一保持在 100%。这是限制性能吗?

When running Numba code on a CUDA GPU, I notice one of my CPU cores stays at 100%. Is this limiting performance?

我有一个计算量很大的测试代码,我 运行 在 GPU 上使用 Numba。我注意到虽然那是 运行ning,但我的一个 CPU 核心达到 100% 并一直保持在那里。 GPU 似乎也是 100%。您可以在下面的屏幕截图中看到两者。

我的基准代码如下:

from numba import *
import numpy as np
from numba import cuda
import time


def benchmark():
    input_list = np.random.randint(10, size=3200000).astype(np.intp)
    output_list = np.zeros(input_list.shape).astype(np.intp)

    d_input_array = cuda.to_device(input_list)
    d_output_array = cuda.to_device(output_list)

    run_test[32, 512](d_input_array, d_output_array)

    out = d_output_array.copy_to_host()
    print('Result: ' + str(out))


@cuda.jit("void(intp[::1], intp[::1])", fastmath=True)
def run_test(d_input_array, d_output_array):
    array_slice_len = len(d_input_array) / (cuda.blockDim.x * cuda.gridDim.x)
    thread_coverage = cuda.threadIdx.x * array_slice_len
    slice_start = thread_coverage + (cuda.blockDim.x * cuda.blockIdx.x * array_slice_len)

    for step in range(slice_start, slice_start + array_slice_len, 1):
        if step > len(d_input_array) - 1:
            return

        count = 0
        for item2 in d_input_array:
            if d_input_array[step] == item2:
                count = count + 1
        d_output_array[step] = count


if __name__ == '__main__':
    import timeit
    # make_multithread(benchmark, 64)
    print(timeit.timeit("benchmark()", setup="from __main__ import benchmark", number=1))

如果安装了 python 3.7、Numba 和 codatoolkit,则可以 运行 重现上面的代码。我在 Linux Mint 20。

我有 32 个内核 - 一个 100% 占用而其他人都闲着似乎不太对。

我想知道为什么会这样,是否有办法让其他内核帮助提高性能?

我如何调查是什么占用了 100% 的单核并了解发生了什么?

从主机线程的角度来看,CUDA 内核启动(和一些其他操作)是异步。正如您所说,您是 运行 GPU 工作的计算密集型部分。

因此主机线程除了启动一些工作并等待它完成外,无事可做。这里的等待过程是一个 spin-wait 这意味着 CPU 线程处于紧密循环中,等待状态条件改变。

CPU 线程将在此处触发自旋等待:

out = d_output_array.copy_to_host()

这是内核启动后的代码行,它期望将(有效的)结果从 GPU 复制回 CPU。为了使其工作,CPU 线程必须在那里等待,直到结果准备就绪。 Numba 在 GPU 和 CPU activity 之间通过 阻塞 同步操作实现了这一点。因此,在程序的大部分时间里,CPU 线程实际上在该行代码处等待。

此等待占用该线程的 100% activity,因此一个核心被视为已充分利用。

没有任何意义或理由尝试将此“工作”“分发”给多个 threads/cores,因此这不是您建议的“性能”问题。

任何显示热点或使用 PC 采样的 CPU 分析器都应该能够为您提供这方面的图片。该行代码应该显示在您的 CPU/core/thread.

最常访问的代码行列表的顶部附近