mirror of
https://github.com/XuehaiPan/nvitop.git
synced 2026-05-15 14:15:55 -06:00
[GH-ISSUE #83] [BUG] nvidia-smi pmon 和 nvitop -o 输出的 sm % 不一致且有较大差异 #50
Labels
No labels
api
bug
bug
cli / tui
dependencies
documentation
documentation
documentation
duplicate
enhancement
exporter
invalid
pull-request
pynvml
question
question
upstream
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference: github-starred/nvitop#50
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @hui-zhao-1 on GitHub (Aug 2, 2023).
Original GitHub issue: https://github.com/XuehaiPan/nvitop/issues/83
Originally assigned to: @XuehaiPan on GitHub.
Required prerequisites
What version of nvitop are you using?
1.2.0
Operating system and version
CentOS Linux 7 (Core)
NVIDIA driver version
470.129.06
NVIDIA-SMI
Python environment
3.10.12 (main, Jul 5 2023, 18:54:27) [GCC 11.2.0] linux
gpustat==1.1
nvidia-ml-py==11.470.66
nvitop==1.2.0
Problem description
分別使用 nvidia-smi pmon -i 7 和 nvitop -o 7 两个命令,观察 7 号 gpu 上的 sm% 发现两者有较大差别
nvidia-smi pmon -i 7 显示,大部分时间 sm% 为 0 偶尔出现 几个不为0 的点,且每次都超过 10%

nvitop -o 7 显示,大部分时间的使用率都为 10% 以下,偶尔出现几个 0%

查看了源代码,怀疑跟 https://github.com/XuehaiPan/nvitop/blob/main/nvitop/api/device.py line 1706 有关
这里计算时间戳的时候,有个 - 2_000_000 的操作
我单独抽取这部分代码,写了一个测试用例,发现, - 2_000_000 会对查询出的 sm% 有影响
Steps to Reproduce
Traceback
Logs
Expected behavior
我没有看懂,https://github.com/XuehaiPan/nvitop/blob/main/nvitop/api/device.py line 1706 计算时间戳的时候,为什么要 - 2_000_000 ,所以不确定我的理解对不对,也不确定是不是跟系统或者版本有关
我只是发现 nvidia-smi pmon -i 7 和 nvitop -o 7 的输出不一致,期望的输出应该是一致的
Additional context
https://www.clear.rice.edu/comp422/resources/cuda/pdf/nvml.pdf 的 155 页解释了 nvmlDeviceGetProcessUtilization 的入参中,时间戳的含义。
我的猜测是,nvidia 维护了一个 最近 n 秒的 sm % 的 buff,查询的时候
如果传递的timestamp 是 0 就会返回buff 里时间戳最小的一条记录
如果传递的tiemstamp 为 x,就会返回 大于等于 x 的 时间戳最小的记录
所以,如果每次查询出的时间戳,都 -2_000_000 的话,下次查询出来的还是相同的记录
直到 buff 满了,把之前查询的记录刷掉了,才会返回此时 buffer 的最新数据
纯属猜想,辛苦大佬帮忙解答,万分感谢!!
感谢大佬作出如此好用的工具!!
@XuehaiPan commented on GitHub (Aug 2, 2023):
@2581543189 感谢提问!
ec53de75b4/nvitop/api/device.py (L1699-L1714)这里额外减
2_000_000(即 2 秒),是为了使得每次 API 调用都尽可能有 sample 返回。这一操作确实会导致该 utilization rate 没法完全反应实时值。另外若某个 pid 对应的进程无 sample 返回,则在 1714 行会将所有 utilization rate 置为 0。若将 timeStamp 设置得过高,可能导致 GPU 有搜集到 sample 但无返回值的情况。注:根据
man nvidia-smi的文档,GPU Utilization 采样率为 1-1/6 秒,估计 Process Utilization 的采样率也在差不多的量级上。NVIDIA NVML 文档:GRID Virtualization APIs
nvmlDeviceGetProcessUtilization@hui-zhao-1 commented on GitHub (Aug 3, 2023):
我想用一个例子说明这样做的坏处:
上面是一个 cuda 程序,可以通过 nvcc nvitop-test.cu -o nvitop-test -std=c++11 进行编译
这个程序的逻辑是,休眠 10S 然后提交一个 kernel 到 gpu 去运行,我的测试机 v100 执行这个kernel 会花费 2s
对应的日志是:
然后,我写一个 python 程序,把 nvitop 的 sm% 信息收集到 prometheus 中,用grafana 展示出曲线图来说明问题
具体采集监控的代码如下:
采集完信息以后,这个进程的 sm 使用率 监控如下图所示:
@hui-zhao-1 commented on GitHub (Aug 3, 2023):
这个程序明明是 休眠 10S 然后工作 2S ,且工作的时候,gpu 使用率是 100%
结果nvitop 统计的结果是,gpu 一直在工作,没有休眠,且使用率在 20% 左右
并没有真实的反应 gpu 的使用情况
@hui-zhao-1 commented on GitHub (Aug 3, 2023):
下图是 nvidia-smi pmon 的结果

下图是 https://github.com/NVIDIA/dcgm-exporter 收集的结果,由于采集的间隔是 10s 所以并不准确,但是整体曲线的形状是正确的:
@XuehaiPan commented on GitHub (Aug 3, 2023):
@2581543189 感谢提供如此详细的复现脚本!(我更新了一下你的 comment 的 Markdown 格式以提高可读性。)
你将
- 2_000_000去除或减小值后能解决你说的问题吗?我也在本地测试一下结果。此处的平均处理为 NVML 内部机制,我未发现有详细文档说明该问题。对于高采样率下的应用场景,额外的 2s 平滑确实可能引入问题。
另外我发现你的复现脚本中使用了:
而
nvitop.gui子模块中的 API 并不对外暴露,并且使用了 GPL-3.0 协议(nvitop.api为 Apache-2.0 协议)。可改为:@hui-zhao-1 commented on GitHub (Aug 3, 2023):
可以用下面的代码验证:
运行之前的 cuda 程序,如果保留
- 2_000_000的话,输出如下:如果删除
- 2_000_000的话,输出如下:@hui-zhao-1 commented on GitHub (Aug 3, 2023):
@XuehaiPan commented on GitHub (Aug 3, 2023):
@2581543189 我开了一个 PR 来删除这个额外的 -2s 的时间值。你可以试试:
需要注意的是,若在
t时刻调用了device.processes(),则device._timestamp = t。再过了δt之后调用device.processes()方法时,使用的 timestamp 为t而不是t + δt附近的值。在δt比较大的时候(如 >2s),依然会产生数据被平滑的情况。另外,使用
nvidia-smi pmon或者开启 daemon 进程会改变 NVML 的采样率,目前我还不太清楚这是否会对结果产生影响。@hui-zhao-1 commented on GitHub (Aug 4, 2023):
我使用
重新安装 nvitop 以后,按照之前回复中 cuda 程序的例子,收集监控数据,并没有什么变化,收集到的监控信息如下所示:

然后我就想,如果每次查询process 的时候,_timestamp 不传递上次sample 的时间,而是直接传递当前时间,是否就可以忽略
δt的影响,于是我 fork 了这个仓库,并进行了对应的修改:使用下面命令安装以后,收集到的统计信息符合预期
监控信息如下图:

@XuehaiPan commented on GitHub (Aug 4, 2023):
@2581543189 感谢新的反馈。我更新了 PR #85 中的实现,即始终使用 epoch timestamp 来调用 NVML API:
您可以试试:
目前还不太清楚这种过于激进的 timestamp 策略(即始终使用调用时刻的 timestamp)是否会导致 sample buffer 中始终为空,或者大概率为空。
nvtop内部的实现是使用上次采样得到的所有 sample 中最大的 timestamp 来作为下次调用时的 timestamp:be47f8c560/src/extract_gpuinfo_nvidia.c (L571-L608)更新: 我这边的本地测试表明直接使用
timestamp = time.time_ns() // 1000会导致 buffer 大部分情况下为空而无 sample 返回。最新的 commit 额外增加了一个 1/4 秒的间隔:@hui-zhao-1 commented on GitHub (Aug 4, 2023):
我这边测试也发现了相同的问题
https://github.com/XuehaiPan/nvitop/compare/main...2581543189:nvitop:now-timestamp这个改动中的 int(datetime.datetime.now().timestamp()) 这个操作,相当于随机对 now 减小了 0~999ms ,监控时间拉长以后,也发现了很多采样为空的现象:用
pip3 install git+https://github.com/XuehaiPan/nvitop.git@process-utilization测试,采样为空的现象更加明显我很好奇,为什么 nvidia-smi pmon 就没有这个问题,想要看它是怎么实现的,但是 google 发现 nvidia-smi 并不开源
目前感觉 使用 nvmlDeviceGetProcessUtilization 这个方法,无论 lastSeenTimeStamp 怎么传递,都无法准确的反应 nvitop-test 这个程序 gpu 的真实 sm 使用情况
@XuehaiPan commented on GitHub (Aug 4, 2023):
@2581543189 我在新的 commit 中额外增加了 1/4 秒的间隔,我本地测试效果还比较好。如下是使用你 https://github.com/XuehaiPan/nvitop/issues/83#issuecomment-1663404181 中提供的测试程序(修改了部分参数)。左边为 PR #85, 右边为 main (v1.2.0):
相比于 v1.2.0,修改后的程序的延迟明显更小。图形更符合方波波形,峰两遍的斜坡更窄。
@hui-zhao-1 commented on GitHub (Aug 4, 2023):
增加了 1/4 秒的间隔 的代码我这边验证也是正常的

之前完全采不到样的截图是我自己操作失误导致的,工具是正常的
@XuehaiPan commented on GitHub (Aug 4, 2023):
好的!感谢反馈!