summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/semfix_uvmt.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/guest-diag/semfix_uvmt.py')
-rwxr-xr-xtools/guest-diag/semfix_uvmt.py31
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