summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-12 14:56:11 -0400
committerArthur Hanson Rasmusson <arthur@vgpu.io>2026-10-12 14:56:11 -0400
commiteea7829f7aa00e772e1568f8e46d7334b7d5ac67 (patch)
treef214beb3e2c37236674b74f0a306b52412c192f2 /tools
parent2a5621c8ac5c11fd4c41300a88c4fa08c03c5079 (diff)
downloadopen-iov-eea7829f7aa00e772e1568f8e46d7334b7d5ac67.tar.gz
open-iov-eea7829f7aa00e772e1568f8e46d7334b7d5ac67.zip
guest-diag: seed channel-event sets from the trace ring on client switch
clear_trace() on a pid switch dropped exactly the one-shot uvmt/uvch events of the new client when they landed in the switch instant; the pipe reader then never saw them and the whole session ran with an empty sem set (r126: vecadd_loop sem=0 for minutes while its CE entries paid the 8 s grace). Scan the ring tail once per switch and seed the sets instead - stale kptrs that are also re-learned resolve to no content and are deferred by the candidate scoring.
Diffstat (limited to 'tools')
-rw-r--r--tools/guest-diag/guest_pin_stream.py50
1 files changed, 41 insertions, 9 deletions
diff --git a/tools/guest-diag/guest_pin_stream.py b/tools/guest-diag/guest_pin_stream.py
index b031733..c0cf485 100644
--- a/tools/guest-diag/guest_pin_stream.py
+++ b/tools/guest-diag/guest_pin_stream.py
@@ -807,15 +807,41 @@ def resolve_channel_pins(kc, ch, out):
-def clear_trace():
- """Drop stale ring events so the fallback tail reader cannot re-learn a
- previous client's freed sems after a client switch. The new client's
- events are delivered fresh through the consuming trace_pipe reader."""
+def seed_events_from_trace(seen_sems, seen_pbs, seen_chs):
+ """One-shot tail scan of the trace ring after a pid switch / start.
+
+ The uvmt/uvbp/uvch kprobe events are one-shot per object, and the
+ trace_pipe reader only sees events that arrive after it attaches: a
+ client whose channels are registered in the instant around the scanner's
+ pid switch would otherwise never appear in the sets (observed r126:
+ vecadd_loop ran for minutes with sem=0 while its CE entries paid the
+ 8 s grace). The ring keeps recent events, so scan its tail once and add
+ every distinct kptr. Stale previous-client pointers that are also
+ re-learned are harmless: their chains no longer resolve to content
+ (the mem candidates are scored and deferred).
+ """
try:
- with open(TRACE, "w") as f:
- f.write("")
- except OSError:
- pass
+ out = subprocess.run(["tail", "-c", "1048576", TRACE],
+ capture_output=True, timeout=10).stdout
+ except Exception:
+ return 0
+ n = 0
+ for m in re.finditer(rb"sem=0x([0-9a-fA-F]+)", out):
+ v = int(m.group(1), 16)
+ if v not in seen_sems:
+ seen_sems.add(v)
+ n += 1
+ for m in re.finditer(rb"pb=0x([0-9a-fA-F]+)", out):
+ v = int(m.group(1), 16)
+ if v not in seen_pbs:
+ seen_pbs.add(v)
+ n += 1
+ for m in re.finditer(rb"ch=0x([0-9a-fA-F]+)", out):
+ v = int(m.group(1), 16)
+ if v not in seen_chs:
+ seen_chs.add(v)
+ n += 1
+ return n
class TraceReader:
@@ -1190,10 +1216,16 @@ def main():
# emitted as if they were the new client's counters.
CHAN_PUTS.clear()
PUT_LAST.clear()
- clear_trace()
tracer.reset()
RESOLVED_KC_PB.clear()
KC_PB_STATE.clear()
+ # One-shot: recover the new client's one-shot channel events
+ # from the trace ring (they can fall in the switch instant and
+ # be invisible to the pipe reader; the old clear_trace() made
+ # that permanent - part of the r126 stall class).
+ _seeded = seed_events_from_trace(seen_sems, seen_pbs, seen_chs)
+ if _seeded:
+ dbg("switch seed: +%d event kptr(s)" % _seeded)
if sock is not None:
try:
sock.sendall(("#pid %d\n" % pid).encode())