summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/semfix_uvmt.py
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-29 15:24:31 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-09-29 15:24:31 -0400
commit8d45a99fe54cb2b19b3024fd975ab11574611c3e (patch)
tree43615ee128d2687b2f7093f95597cf9379484c4a /tools/guest-diag/semfix_uvmt.py
parent1895679334371c5a89dd5cb715c980ade6559c72 (diff)
downloadopen-iov-8d45a99fe54cb2b19b3024fd975ab11574611c3e.tar.gz
open-iov-8d45a99fe54cb2b19b3024fd975ab11574611c3e.zip
guest-diag: stream uvmt sems over vsock (no guest-agent race); dump channel last release VA; larger push log budget
Diffstat (limited to 'tools/guest-diag/semfix_uvmt.py')
-rwxr-xr-xtools/guest-diag/semfix_uvmt.py89
1 files changed, 81 insertions, 8 deletions
diff --git a/tools/guest-diag/semfix_uvmt.py b/tools/guest-diag/semfix_uvmt.py
index 0d31394..fb0e92e 100755
--- a/tools/guest-diag/semfix_uvmt.py
+++ b/tools/guest-diag/semfix_uvmt.py
@@ -41,6 +41,53 @@ DLOG = os.environ.get("UVMT_DMESG", "1") == "1"
VMEXEC = os.path.normpath(os.path.join(HERE, "..", "..", "scripts", "vgpu_vm.py"))
COUNTER_LO = int(os.environ.get("COUNTER_LO", "0x20400f000"), 16)
COUNTER_HI = int(os.environ.get("COUNTER_HI", "0x204010000"), 16)
+SEMSTREAM = os.environ.get("SEM_STREAM_FILE", "/tmp/opencode/sem_stream.txt")
+TRACE_EVERY = int(os.environ.get("UVMT_TRACE_EVERY", "5"))
+
+
+class Stream:
+ """Tail the guest scanner's control lines mirrored by pin_gr_stream.py.
+
+ The guest emits "#pid <n>" and "#sem 0x<k>" over vsock; the listener
+ appends them here. This replaces per-loop guest-agent trace reads, which
+ were too slow to catch short-lived tracking semaphores.
+ """
+
+ def __init__(self, path):
+ self.path = path
+ self.off = 0
+ self.sems = []
+ self.pids = []
+
+ def poll(self):
+ try:
+ with open(self.path) as f:
+ f.seek(0, os.SEEK_END)
+ size = f.tell()
+ if size < self.off:
+ self.off = 0
+ f.seek(self.off)
+ data = f.read()
+ self.off = f.tell()
+ except OSError:
+ return [], []
+ new_sems, new_pids = [], []
+ for line in data.splitlines():
+ if line.startswith("#sem"):
+ m = re.search(r"0x([0-9a-fA-F]+)", line)
+ if m:
+ v = int(m.group(1), 16)
+ if v not in self.sems:
+ self.sems.append(v)
+ new_sems.append(v)
+ elif line.startswith("#pid"):
+ m = re.search(r"(\d+)", line)
+ if m:
+ v = int(m.group(1))
+ if v not in self.pids:
+ self.pids.append(v)
+ new_pids.append(v)
+ return new_sems, new_pids
def log(msg):
@@ -191,6 +238,8 @@ def main():
dseen = set()
counter_pids = set()
last_pid = None
+ stream = Stream(SEMSTREAM)
+ loop = 0
def pin_range_once(gpu_vas, cpu, gpa, size=0):
key = tuple(gpu_vas), cpu, size
@@ -200,7 +249,30 @@ def main():
pin_pushbuffer(q, gpu_vas, cpu, gpa, size)
while True:
- sems, pbs, chans = guest_trace()
+ loop += 1
+ sems = set()
+ pbs = set()
+ chans = set()
+
+ new_sems, new_pids = stream.poll()
+ for s in new_sems:
+ log("stream: new uvmt sem 0x%x" % s)
+ for p in new_pids:
+ log("stream: client pid %d" % p)
+ last_pid = p
+ sems.update(stream.sems)
+
+ # The guest-agent trace read is slow under client load; use it only
+ # as a fallback for channel/pushbuffer discovery and to recover sems
+ # the scanner may have missed.
+ if loop % TRACE_EVERY == 0:
+ try:
+ t_sems, t_pbs, t_chans = guest_trace()
+ except Exception:
+ t_sems, t_pbs, t_chans = set(), set(), set()
+ sems.update(t_sems)
+ pbs.update(t_pbs)
+ chans.update(t_chans)
# Poll every sem ever seen: the client's final wait may only appear in
# the trace once, and the trace ring wraps while it spins.
@@ -293,14 +365,15 @@ def main():
dmesg_releases(dseen)
# Pin the completion-counter page of a newly started client, before its
- # first GR pushes decode their releases.
- pid = cdt_pid()
- if pid and pid != last_pid:
- last_pid = pid
- log("counter: client pid %d" % pid)
- if pid and pid not in counter_pids:
+ # first GR pushes decode their releases. The pid comes from the guest
+ # scanner; the guest-agent fallback is only a safety net.
+ if last_pid is None and loop % TRACE_EVERY == 0:
+ last_pid = cdt_pid()
+ if last_pid:
+ log("counter: client pid %d (agent)" % last_pid)
+ if last_pid and last_pid not in counter_pids:
try:
- pin_counter_page(pid, counter_pids)
+ pin_counter_page(last_pid, counter_pids)
except Exception as e:
log("counter: pin failed: %s" % e)