【问题标题】:Determine if cuda device in use?确定是否正在使用 cuda 设备?
【发布时间】:2020-12-29 23:19:51
【问题描述】:

有没有办法直接测试 cuda 设备当前是否被任何内核使用?

我有一个后台线程,它为分形程序在完全占用的情况下启动“原始”cuda 内核。该线程构建了大型图像数组,然后我想让用户平滑地平移、旋转和缩放。

如果 GPU 目前没有用于大图像转换,我的 GUI 线程想使用它,因为它以 100 fps 运行。如果 GPU 正在使用中,我可以回退到使用 CPU 代码,而不是 10-20 fps。

如果在后台线程内核已经运行时使用 GUI 线程 GPU 代码,则 GUI 线程将明显冻结,直到后台内核完成。这种冻结是我试图通过切换到这些帧的 CPU 代码来消除的。我已经研究过中断后台内核,但我看到的解决方案会增加内核的计算成本和/或重置上下文,这两者似乎都过大了。

有没有办法直接(异步)检测 GPU 是否正在使用(任何内核)?我想 GPU 在技术上总是被用作 2-D 显示驱动程序,因此当然不包括该活动。

我的解决方法是在我的程序中设置一个标志来跟踪是否所有内核都已完成。我需要在两个主机线程之间以及程序中模型和视图中最嵌套的对象之间传递该标志。我开始写这篇文章并认为这是一个有点混乱的解决方案,即使这样也并不总是 100% 准确。所以我想知道是否有更好的方法,特别是是否可以在 GUI 线程中直接测试 GPU,从而决定下一帧是使用 GPU 还是 CPU 代码。

我正在使用 python 3.7,通过 cupy 访问 GPU,但我愿意尝试采用 C++ 解决方案。

我查看了文档,但只有 cuda 的基本知识,感觉就像大海捞针: https://docs.nvidia.com/cuda/cuda-runtime-api/group__CUDART__DEVICE.html#group__CUDART__DEVICE

【问题讨论】:

  • 通过对 cuda 流的使用进行一些管理,您也许可以使用cudaStreamQuery()casual glance 表明 done 属性是在 cupy 中实现的方式,但我没有完整的解决方案。
  • 另外,我不得不指出,如果您在完全异步的狂野西部环境中运行,您有独立的异步工作提交者,您可以对 GPU 的状态进行采样,发现它是空闲,然后一纳秒后,另一个工作提交者可以向该 GPU 提交一些东西。所以我怀疑这种异步采样方法是一种强大的技术。
  • @RobertCrovella 第一个建议看起来很有希望。我会尝试一下,稍后再发表评论。我只使用默认的蒸汽,所以应该很简单。
  • 第二个建议,你是说为纳秒内核启动一个新的python线程吗?如果内核在短时间内成功运行,那么该线程是否会在主线程中发出将 gpu_available 标志更新为 True 的事件?纳秒内核,即使在单独的流中运行,如果 GPU 被占用,当然也不会运行,因为我的主内核正在满载运行。
  • 即使后台内核正在运行,您也可以使用流优先级让 GUI 内核正常工作,但这可能取决于许多不可能的内核特性从你的问题中推断出来,这似乎没有暴露在cupy中。另一种方法是对工作提交进行一些控制。创建一个包装工作提交函数,1.获取全局锁 2.启动工作 3.启动回调释放全局锁。如果您可以从 GUI 线程获取全局锁,请在此处启动。否则,使用 CPU。

标签: cuda cupy


【解决方案1】:

这是我在 @RobertCrovella 的帮助下使用的解决方案。

import cupy as cp

stream_done: bool = cp.cuda.get_current_stream().done

if stream_done or worker_ready:
    # use cupy to draw next frame
else:
    # use numpy to draw next frame

其中 worker_ready 是从后台工作 GPU 线程传递的布尔值,指示它的活动。

对于 stream_done,请参阅docs。在我的程序中,我只使用 1 个 cuda 流,即(未指定的)默认流。否则我想你需要根据问题测试每个流。

经过大量测试,我发现:

cp.cuda.get_current_stream().done 在内核运行后立即在后台线程中为 True,但随后可能变为 False,尽管我的代码没有在 True 和 False 状态之间调用 GPU,但我需要进行测试。我无法解释这种行为,但我发现我不能仅仅依靠 stream_done。我的测试表明:如果 stream_done 在需要的时候为 True,那么使用 GPU 总是安全的;如果 stream_done 为 False,则使用 GPU 可能安全也可能不安全。

我还让后台线程在启动和停止时触发一个事件,该事件会更改 GUI 线程的 worker_ready 布尔值。我的测试表明 worker_ready 在确定是否可以使用 GPU 方面比 stream_done 更准确。在 stream_done 为 True 且 worker_ready 为 False 的情况下,我的测试显示 GPU 代码也会快速运行,大概是因为后台线程在那个时间点正在执行 CPU 代码。

因此,我提出的问题的最佳解决方案是在满足任一条件时使用 GPU 代码。然而,即使这样也没有消除我试图消除的视觉滞后。

我试图解决的问题是,当后台进程在 GPU 上运行并且用户尝试平移时,偶尔会出现至少 0.5 秒的明显延迟。我试图通过测量从鼠标按下到显示的平移图像的时间来量化这种滞后。测得的时间延迟为 0.1 秒或更短。因此,无论鼠标点击后代码有多快,无论是使用 GPU 还是 CPU,都无法消除延迟。 对我来说,这意味着启动鼠标按下事件本身在 GPU 被占用时会延迟触发。这大概是因为 GPU 也在运行显示驱动程序。除此之外,我没有任何确凿的证据:

  • 如果后台线程没有运行,那么延迟就会被移除。
  • 将内核缩短几个数量级并没有减少延迟。
  • 增加 block_size 以摆脱完全占用似乎在大多数情况下消除了延迟,尽管它并没有完全消除它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-03
    • 2013-08-24
    • 2015-05-20
    相关资源
    最近更新 更多