From 3031f72e6408a894c05d3cf1679e4bb7d074d989 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Tue, 29 Sep 2026 13:18:00 -0400 Subject: guest-diag: resolve pushbuffer from uvpbf kprobe pointer (deterministic) --- tools/guest-diag/semfix_watch.py | 45 ++++++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 6 deletions(-) (limited to 'tools') diff --git a/tools/guest-diag/semfix_watch.py b/tools/guest-diag/semfix_watch.py index 0de5cad..8fd534d 100644 --- a/tools/guest-diag/semfix_watch.py +++ b/tools/guest-diag/semfix_watch.py @@ -87,16 +87,34 @@ def is_gpu(v): return v and GPU_VA_LO <= v < GPU_VA_HI -def guest_sems(): - """Kernel pointers of tracking semaphores the client is spinning on.""" +def guest_trace(): + """(sem kptrs, pushbuffer kptrs) from the trace ring, then clear it.""" cmd = ("sudo sh -c 'echo > /sys/kernel/tracing/trace; sleep 2; " - "grep uvmt /sys/kernel/tracing/trace | tail -4'") + "grep -E \"uvmt|uvpb\" /sys/kernel/tracing/trace | tail -8'") try: out = subprocess.run([VMEXEC, "exec", cmd], capture_output=True, text=True, timeout=90).stdout except Exception: - return set() - return {int(m, 16) for m in re.findall(r"sem=0x([0-9a-fA-F]+)", out)} + return set(), set() + sems = {int(m, 16) for m in re.findall(r"sem=0x([0-9a-fA-F]+)", out)} + pbs = {int(m, 16) for m in re.findall(r"pb=0x([0-9a-fA-F]+)", out)} + return sems, pbs + + +def resolve_pb_ptr(q, pb): + """pushbuffer pointer -> rm_mem -> vas[] -> (gpu_vas, cpu, gpa).""" + mem = q.read64(pb + 8) + if not mem or not is_kern(mem[0]): + return [], None, None + vas = q.read64(mem[0] + 0x10, 16) + gpu_vas = [v for v in vas if PUSHBUF_VA_LO <= v < PUSHBUF_VA_HI] + cpu = next((v for v in vas if is_kern(v)), None) + if not gpu_vas or not cpu: + return [], None, None + gpa = q.gva2gpa(cpu) + if not gpa: + return [], None, None + return gpu_vas, cpu, gpa def pin(va, pa): @@ -201,10 +219,25 @@ def main(): interval = float(sys.argv[1]) if len(sys.argv) > 1 else 3.0 q = Qmp(QMP_SOCK) seen = set() + seen_pb = set() pb_done = False print("semfix: watching (interval %.1fs)" % interval, flush=True) while True: - for sem in guest_sems() - seen: + sems, pbs = guest_trace() + if not pb_done: + for pb in pbs - seen_pb: + seen_pb.add(pb) + try: + gpu_vas, cpu, gpa = resolve_pb_ptr(q, pb) + except Exception as e: + print("semfix: pb=0x%x resolve failed: %s" % (pb, e), flush=True) + continue + if gpu_vas: + pin_pushbuffer(q, gpu_vas, cpu, gpa) + pb_done = True + break + print("semfix: pb=0x%x no pushbuffer rm_mem (retry)" % pb, flush=True) + for sem in sems - seen: try: pairs = resolve_sem_pool(q, sem) except Exception as e: -- cgit v1.2.3