summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-11 21:08:05 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-11 21:08:05 -0400
commitd2c9054b096e63ca3dd4f890514639f7efd82c3f (patch)
tree14cacf558e6ce39675f6d5f8f516d833043f2e14 /tools
parent66d7e5f93ed0f3139ba4a6635bf355a4c0052a04 (diff)
downloadopen-iov-d2c9054b096e63ca3dd4f890514639f7efd82c3f.tar.gz
open-iov-d2c9054b096e63ca3dd4f890514639f7efd82c3f.zip
guest-diag: scanner detects arbitrary CUDA clients by nvidia fds
The guest pin scanner only tracked processes whose comm matched CLIENT_PREFIXES (cdt,va,victory). An arbitrary CUDA binary (e.g. /tmp/smiley) was invisible: no pages streamed, no VA->PA pins injected, the service could not read its pushes and the client hung in cudaMalloc/uvm_tracker_wait. Detect compute clients by the CUDA device they hold open (/dev/nvidia-uvm preferred, then any /dev/nvidia*), with the prefix match kept as the first-choice path.
Diffstat (limited to 'tools')
-rw-r--r--tools/guest-diag/guest_pin_stream.py48
1 files changed, 44 insertions, 4 deletions
diff --git a/tools/guest-diag/guest_pin_stream.py b/tools/guest-diag/guest_pin_stream.py
index 031271c..29ef114 100644
--- a/tools/guest-diag/guest_pin_stream.py
+++ b/tools/guest-diag/guest_pin_stream.py
@@ -632,18 +632,42 @@ def new_sems(seen):
return found
+def nvidia_fds(pid):
+ """CUDA device fds this pid holds: 'uvm', 'gpu', or None.
+
+ /dev/nvidia-uvm marks a compute client (the CUDA runtime opens it at
+ context init; nvidia-smi and persistenced do not), so a process holding
+ it is a real client regardless of its binary name.
+ """
+ kind = None
+ try:
+ fddir = '/proc/%s/fd' % pid
+ for fd in os.listdir(fddir):
+ try:
+ tgt = os.readlink(os.path.join(fddir, fd))
+ except OSError:
+ continue
+ if tgt.startswith('/dev/nvidia-uvm'):
+ return 'uvm'
+ if tgt.startswith('/dev/nvidia'):
+ kind = 'gpu'
+ except OSError:
+ pass
+ return kind
+
+
def cdt_pid():
prefixes = tuple(p for p in os.environ.get("CLIENT_PREFIXES",
"cdt,va,victory").split(",") if p)
best = None
+ uvm = None
+ gpu = None
for d in os.listdir('/proc'):
if not d.isdigit():
continue
try:
with open('/proc/%s/comm' % d) as f:
name = f.read().strip()
- if not any(name.startswith(p) for p in prefixes):
- continue
# Skip zombies: a defunct previous client keeps its comm and
# would otherwise shadow the live client (pagemap reads then fail
# and no pins are ever streamed).
@@ -652,10 +676,26 @@ def cdt_pid():
rp = st.rfind(')')
if rp >= 0 and st[rp + 2:rp + 3] == 'Z':
continue
- best = int(d)
+ if any(name.startswith(p) for p in prefixes):
+ best = int(d)
+ continue
+ # Arbitrary CUDA binaries (any comm) are clients too: match by
+ # the CUDA device they hold open so streaming never depends on
+ # the binary's name. Prefer a UVM holder (compute client) over a
+ # plain /dev/nvidia0 holder (nvidia-smi, persistenced); the last
+ # match wins, which is the newest client when several overlap.
+ kind = nvidia_fds(d)
+ if kind == 'uvm':
+ uvm = int(d)
+ elif kind == 'gpu':
+ gpu = int(d)
except OSError:
pass
- return best
+ if best is not None:
+ return best
+ if uvm is not None:
+ return uvm
+ return gpu
def scan_window(fd, lo, hi, span, out):