summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag
diff options
context:
space:
mode:
Diffstat (limited to 'tools/guest-diag')
-rw-r--r--tools/guest-diag/guest_pin_stream.py43
-rw-r--r--tools/guest-diag/pin_gr_stream.py36
2 files changed, 63 insertions, 16 deletions
diff --git a/tools/guest-diag/guest_pin_stream.py b/tools/guest-diag/guest_pin_stream.py
index 3b7d9b1..f89ed4a 100644
--- a/tools/guest-diag/guest_pin_stream.py
+++ b/tools/guest-diag/guest_pin_stream.py
@@ -40,6 +40,12 @@ SPAN = int(os.environ.get("STREAM_SPAN", "0x80000"), 16)
LO2 = int(os.environ.get("STREAM_LO2", "0x120000000"), 16)
HI2 = int(os.environ.get("STREAM_HI2", "0x121400000"), 16)
SPAN2 = int(os.environ.get("STREAM_SPAN2", "0x180000"), 16)
+# UVM semaphore pool window: the tracker pool word lives at
+# 0x121000000 + 4*idx, above the CE window head span (LO2+SPAN2 =
+# 0x120180000), so scan_window never reaches it. Scan every 4 KB page of
+# [POOL_LO, POOL_HI) directly - cheap (16 pages) and host-visible as pins.
+POOL_LO = int(os.environ.get("STREAM_POOL_LO", "0x121000000"), 16)
+POOL_HI = int(os.environ.get("STREAM_POOL_HI", "0x121010000"), 16)
# UVM system-memory AVMAs: the client's sysmem buffers (the DtoH staging
# buffer among them) are /dev/zero mappings at high GPU VAs (e.g.
# 0x79c21c800000). They are not inside the two fixed windows, and only the
@@ -128,7 +134,7 @@ def new_sems(seen):
def cdt_pid():
prefixes = tuple(p for p in os.environ.get("CLIENT_PREFIXES",
- "cdt,va").split(",") if p)
+ "cdt,va,victory").split(",") if p)
for d in os.listdir('/proc'):
if not d.isdigit():
continue
@@ -167,6 +173,35 @@ def scan_window(fd, lo, hi, span, out):
base += REGION
+def scan_range(fd, lo, hi, out):
+ """Present pages of one explicit VA range, every 4 KB page.
+
+ Same pagemap present/PFN/PAMAX filtering as scan_window, but with no
+ REGION alignment or head-span limit: walks [lo, hi) directly. Used for
+ the UVM semaphore pool window, which sits past the CE head span.
+ """
+ va = lo & ~0xFFF
+ while va < hi:
+ n = min(BATCH, (hi - va) // 0x1000)
+ if n <= 0:
+ break
+ os.lseek(fd, (va // 4096) * 8, 0)
+ data = os.read(fd, n * 8)
+ got = len(data) // 8
+ if got <= 0:
+ break
+ for i in range(got):
+ e = int.from_bytes(data[i * 8:i * 8 + 8], 'little')
+ if not ((e >> 63) & 1):
+ continue
+ pfn = e & ((1 << 55) - 1)
+ pa = pfn << 12
+ if not pa or (PAMAX and pa >= PAMAX):
+ continue
+ out[va + i * 0x1000] = pa
+ va += got * 0x1000
+
+
def scan_vmas(fd, pid, out):
"""Present pages of the client's high-VA nvidia//dev/zero mappings.
@@ -237,6 +272,8 @@ def scan(pid):
scan_window(fd, LO, HI, SPAN, out)
if HI2 > LO2:
scan_window(fd, LO2, HI2, SPAN2, out)
+ if POOL_HI > POOL_LO:
+ scan_range(fd, POOL_LO, POOL_HI, out)
if VMA_EVERY and scan.loop % VMA_EVERY == 0:
scan_vmas(fd, pid, out)
finally:
@@ -304,7 +341,7 @@ def main():
if cpa and (not PAMAX or cpa < PAMAX):
cur[0x20400f000] = cpa
new = [(va, pa) for va, pa in cur.items() if seen.get(va) != pa]
- seen = cur
+ pending_cur = cur
lines = []
for ctl in tracer.drain():
if ctl.startswith("#sem"):
@@ -321,6 +358,7 @@ def main():
except OSError:
pass
if not new and not lines:
+ seen = pending_cur
time.sleep(INTERVAL)
continue
if new:
@@ -350,6 +388,7 @@ def main():
continue
try:
sock.sendall(payload)
+ seen = pending_cur
except OSError:
sock.close()
sock = None
diff --git a/tools/guest-diag/pin_gr_stream.py b/tools/guest-diag/pin_gr_stream.py
index d8b6b61..7f8e4b8 100644
--- a/tools/guest-diag/pin_gr_stream.py
+++ b/tools/guest-diag/pin_gr_stream.py
@@ -58,6 +58,8 @@ def _start_cmd():
with open(GUEST_SCRIPT) as f:
b64 = subprocess.run(["base64", "-w0"], stdin=f,
capture_output=True, text=True).stdout
+ prefixes = os.environ.get("CLIENT_PREFIXES", "cdt,va,victory")
+ vma_every = os.environ.get("STREAM_VMA_EVERY", "1")
return ("echo '%s' | base64 -d > /tmp/guest_pin_stream.py; "
"if [ -f /tmp/guest_pin_stream.pid ]; then "
"p=$(cat /tmp/guest_pin_stream.pid 2>/dev/null); "
@@ -65,10 +67,12 @@ def _start_cmd():
"/proc/$p/cmdline 2>/dev/null && sudo kill $p 2>/dev/null; "
"fi; "
"sudo rm -f /tmp/guest_pin_stream.pid; "
- "sudo setsid nohup python3 /tmp/guest_pin_stream.py %d %d %s %s %s "
+ "sudo setsid nohup env CLIENT_PREFIXES='%s' "
+ "STREAM_VMA_EVERY='%s' "
+ "python3 /tmp/guest_pin_stream.py %d %d %s %s %s "
">/tmp/guest_pin_stream.log 2>&1 & sleep 2; "
"sudo cat /tmp/guest_pin_stream.pid 2>/dev/null"
- % (b64, 2, PORT, LO, HI, PAMAX))
+ % (b64, prefixes, vma_every, 2, PORT, LO, HI, PAMAX))
def install_and_start():
@@ -189,18 +193,22 @@ def _flush(runs, seen):
"echo 'FAIL 0x%x 0x%x 0x%x'"
% (va, pa, n * 0x1000, PARAM, va, pa, n * 0x1000))
failed = set()
- try:
- r = subprocess.run(["sudo", "-n", "sh", "-c", "\n".join(script)],
- capture_output=True, text=True, timeout=60)
- for line in r.stdout.splitlines():
- m = re.match(r"FAIL (0x[0-9a-f]+) (0x[0-9a-f]+) (0x[0-9a-f]+)",
- line.strip())
- if m:
- failed.add((int(m.group(1), 16), int(m.group(2), 16),
- int(m.group(3), 16) // 0x1000))
- except Exception as e:
- log("batch inject failed: %s" % e)
- failed = set(todo)
+ CHUNK = 200
+ for start in range(0, len(script), CHUNK):
+ batch = script[start:start + CHUNK]
+ try:
+ r = subprocess.run(["sudo", "-n", "sh", "-c", "\n".join(batch)],
+ capture_output=True, text=True, timeout=60)
+ for line in r.stdout.splitlines():
+ m = re.match(r"FAIL (0x[0-9a-f]+) (0x[0-9a-f]+) (0x[0-9a-f]+)",
+ line.strip())
+ if m:
+ failed.add((int(m.group(1), 16), int(m.group(2), 16),
+ int(m.group(3), 16) // 0x1000))
+ except Exception as e:
+ log("batch inject failed: %s" % e)
+ for va, pa, n in todo[start:start + CHUNK]:
+ failed.add((va, pa, n))
pages = 0
for va, pa, n in todo: