summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/guest_pin_stream.py
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-15 01:19:12 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-15 01:19:12 -0400
commit3ae0688d5185305f2d9e2caa06415eab0dc0c1d0 (patch)
treedb43d2bdf0e36bb0eb58c3a23b3577ec516c367a /tools/guest-diag/guest_pin_stream.py
parent8479659ce21bfae6639194d533ca925ba9fdd9b6 (diff)
downloadopen-iov-3ae0688d5185305f2d9e2caa06415eab0dc0c1d0.tar.gz
open-iov-3ae0688d5185305f2d9e2caa06415eab0dc0c1d0.zip
guest-diag: single-instance scanner start + full-re-assert backoff
r148 ran THREE guest scanners (pin_gr_stream install_and_start retried while a partially-failed first attempt had already started one, and the pid-file kill missed it). Each scanner re-asserted the whole CE pair set every 2 s; with a fully fragmented pair set (descending PAs, one page per line) that is ~2 k debugfs writes/s per scanner, and the guest hit load 19 with clients wedged spinning in userspace. - pin_gr_stream._start_cmd: kill EVERY existing scanner first (pattern assembled at runtime with printf so the command's own cmdline cannot self-match), then start exactly one. - guest_pin_stream._emit_ce_mem_delta: the full re-assert keeps its 1.5 s cadence for the first STREAM_FULLREM_FAST_S seconds of a mem's life (the client-switch flush race), then backs off to STREAM_FULLREM_SLOW_S (10 s) as a safety net. Configurable via env.
Diffstat (limited to 'tools/guest-diag/guest_pin_stream.py')
-rw-r--r--tools/guest-diag/guest_pin_stream.py18
1 files changed, 14 insertions, 4 deletions
diff --git a/tools/guest-diag/guest_pin_stream.py b/tools/guest-diag/guest_pin_stream.py
index 7d07f55..e80751a 100644
--- a/tools/guest-diag/guest_pin_stream.py
+++ b/tools/guest-diag/guest_pin_stream.py
@@ -458,7 +458,9 @@ def _emit_ce_mem_delta(kc, st, out, fresh_map=False):
nowm = time.monotonic()
full = nowm >= st.get("full_next", 0.0)
if full:
- st["full_next"] = nowm + KC_FULLREM_S
+ age = nowm - st.get("resolved_at", nowm)
+ st["full_next"] = nowm + (KC_FULLREM_S if age < KC_FULLREM_FAST_S
+ else KC_FULLREM_SLOW_S)
if fresh_map:
for k in range(npages):
kc._pa_cache.pop(cpu + (k + off) * 0x1000, None)
@@ -680,8 +682,15 @@ KC_REMAP_S = 30.0 # full re-translation sweep (catches remaps)
# whole translatable pair set regardless of the delta, healing host-side
# session-flush wipes (see _emit_ce_mem_delta). Must stay well under the
# host's gsp_sema_ce_grace_ms (8 s) so a wiped-and-needed page is restored
-# inside the hold window.
-KC_FULLREM_S = 1.5
+# inside the hold window. The fast cadence applies to a mem's first
+# KC_FULLREM_FAST_S seconds (the flush race lives at the client switch);
+# after that the re-assert backs off to KC_FULLREM_SLOW_S - a fully
+# fragmented pair set (descending PAs) emits one page per line, and 4 k
+# lines every 2 s saturated a guest under multi-client load (r148: load 19,
+# three scanners from an install race, clients wedged).
+KC_FULLREM_S = float(os.environ.get("STREAM_FULLREM_S", "1.5"))
+KC_FULLREM_FAST_S = float(os.environ.get("STREAM_FULLREM_FAST_S", "45"))
+KC_FULLREM_SLOW_S = float(os.environ.get("STREAM_FULLREM_SLOW_S", "10.0"))
def _chain_mems_at(kc, w):
@@ -870,7 +879,8 @@ def resolve_pb_chain(kc, sem, out):
gpus, cpu, off, npages = params
st = {"mem": mem, "gpu": gpu, "cpu": cpu, "gpus": gpus,
"page_va": cpu, "page_pa": kc.va_to_pa(cpu) or 0,
- "page_off": off, "npages": npages, "last": {}}
+ "page_off": off, "npages": npages, "last": {},
+ "resolved_at": time.monotonic()}
# Fresh translation for the first sweep: the Kcore PA cache may hold
# pairs from before this mem's vmap area was (re)populated.
kc._pa_cache.clear()