diff options
Diffstat (limited to 'tools/guest-diag/semfix_uvmt.py')
| -rwxr-xr-x | tools/guest-diag/semfix_uvmt.py | 31 |
1 files changed, 26 insertions, 5 deletions
diff --git a/tools/guest-diag/semfix_uvmt.py b/tools/guest-diag/semfix_uvmt.py index fba465d..b9f3ac9 100755 --- a/tools/guest-diag/semfix_uvmt.py +++ b/tools/guest-diag/semfix_uvmt.py @@ -32,7 +32,7 @@ from semfix_watch import ( # noqa: E402 Qmp, QMP_SOCK, is_kern, is_gpu, diag_str, guest_trace, resolve_sem_pool, pin, pin_bulk, resolve_from_channel, resolve_from_pushbuffer, resolve_from_sem, resolve_pushbuffer_wide, - pin_pushbuffer, + pin_pushbuffer, PUSHBUF_MAX_PAGES, ) TIMELINE = os.environ.get("TIMELINE", "/tmp/opencode/uvmt_timeline.log") @@ -250,7 +250,7 @@ def main(): seen_sem_pin = set() seen_pb = set() seen_ch = set() - pinned_ranges = set() + pinned_ranges = {} last_state = {} last_seen_t = {} dseen = set() @@ -262,10 +262,22 @@ def main(): def pin_range_once(gpu_vas, cpu, gpa, size=0): key = tuple(gpu_vas), cpu, size - if key in pinned_ranges: + st = pinned_ranges.get(key) + if st is None: + st = pinned_ranges[key] = {"tries": 0, "done": False, + "args": (gpu_vas, cpu, gpa, size)} + if st["done"]: return - pinned_ranges.add(key) - pin_pushbuffer(q, gpu_vas, cpu, gpa, size) + st["tries"] += 1 + pinned = pin_pushbuffer(q, gpu_vas, cpu, gpa, size) + expected = min(max(size >> 12, 1) if size else PUSHBUF_MAX_PAGES, + PUSHBUF_MAX_PAGES) + if pinned >= expected: + st["done"] = True + elif st["tries"] >= 12: + st["done"] = True + log("semfix: pushbuf pin incomplete after %d tries: %d/%d pages" + % (st["tries"], pinned, expected)) while True: loop += 1 @@ -388,6 +400,15 @@ def main(): if DLOG: dmesg_releases(dseen) + # Retry incomplete push-buffer pins: gva2gpa of the kernel vmalloc + # alias fails while the sampled vCPU runs in user mode (PTI), so a + # pass can miss a run of pages that resolves a moment later. Only + # every 8th loop - a full pass costs thousands of QMP reads. + if loop % 8 == 0: + for st in list(pinned_ranges.values()): + if not st["done"] and st["tries"] > 0: + pin_range_once(*st["args"]) + # Pin the completion-counter page of a newly started client, before its # first GR pushes decode their releases. The pid comes from the guest # scanner; the guest-agent fallback is only a safety net. The exec can |
