diff options
| author | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-29 16:14:12 -0400 |
|---|---|---|
| committer | Arthur Hanson Rasmusson <arthur@vgpu.io> | 2026-09-29 16:14:12 -0400 |
| commit | 6d5131e87a2c9cb5c20437669c1917f7be6252b5 (patch) | |
| tree | 43934878bc90db539f697bdb2fe069ab0c484442 /tools/guest-diag/pin_gr_stream.py | |
| parent | 78b8f909784676c5ec6f02a6c48d51ec2a589f96 (diff) | |
| download | open-iov-6d5131e87a2c9cb5c20437669c1917f7be6252b5.tar.gz open-iov-6d5131e87a2c9cb5c20437669c1917f7be6252b5.zip | |
sema-svc: persist GR counter slot per channel; stable slot layout; bulk pin queue 4k
- counter_pa autoreg result is written back to the channel table so later
passes cannot re-target a different slot when the live GR count changes
during teardown; re-registration of the same channel preserves the slot.
- counter slot layout uses the max GR count ever seen in the generation
instead of the shrinking live count.
- sema_map_add queue 64 -> 4096 entries so a full-window pin burst drains
without ENOSPC retries.
- pin_gr_stream: one batched sudo pass per flush (was one process per run,
~4 s for 400 runs), retrying only queue-rejected runs.
- semfix_uvmt: SEMFIX_SKIP_PB=1 skips the blocking push-buffer chain walk
when the vsock window stream already supplies those pages.
Diffstat (limited to 'tools/guest-diag/pin_gr_stream.py')
| -rw-r--r-- | tools/guest-diag/pin_gr_stream.py | 53 |
1 files changed, 45 insertions, 8 deletions
diff --git a/tools/guest-diag/pin_gr_stream.py b/tools/guest-diag/pin_gr_stream.py index 643145b..b80d30a 100644 --- a/tools/guest-diag/pin_gr_stream.py +++ b/tools/guest-diag/pin_gr_stream.py @@ -149,22 +149,59 @@ def main(): def _flush(runs, seen): - """Inject run lines, return number of pages pinned.""" - pages = 0 + """Inject run lines (one batched sudo pass), return number of pages pinned. + + The old implementation spawned one sudo process per run; with ~400 runs + that cost ~4 s, which landed the GR pins after the client's context-init + deadline. The batch writes all runs in a single shell, retrying only the + ones the kernel queue rejected (ENOSPC) individually. + """ + todo = [] for va, pa, n in runs: if seen.get(va) == pa and n == 1: continue + todo.append((va, pa, n)) + if not todo: + return 0 + + def mark(va, pa, n): for i in range(n): seen[va + i * 0x1000] = pa + i * 0x1000 - if not inject(va, pa, n * 0x1000): - for i in range(n): - if inject(va + i * 0x1000, pa + i * 0x1000, 0x1000): - pages += 1 + + script = [] + for va, pa, n in todo: + script.append( + "printf '0x%x,0x%x,0x%x,1' > %s/sema_map_add 2>/dev/null || " + "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) + + pages = 0 + for va, pa, n in todo: + if (va, pa, n) in failed: continue + mark(va, pa, n) pages += n + for va, pa, n in failed: + for i in range(n): + if inject(va + i * 0x1000, pa + i * 0x1000, 0x1000): + mark(va + i * 0x1000, pa + i * 0x1000, 1) + pages += 1 if pages: - log("pinned %d page(s) in %d run(s)" % (pages, len(runs))) - for va, pa, n in runs[:3]: + log("pinned %d page(s) in %d run(s)" % (pages, len(todo))) + for va, pa, n in todo[:3]: log(" va=0x%x -> pa=0x%x (%d)" % (va, pa, n)) return pages |
