summaryrefslogtreecommitdiffstats
path: root/tools/guest-diag/pin_gr_stream.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/guest-diag/pin_gr_stream.py')
-rw-r--r--tools/guest-diag/pin_gr_stream.py58
1 files changed, 51 insertions, 7 deletions
diff --git a/tools/guest-diag/pin_gr_stream.py b/tools/guest-diag/pin_gr_stream.py
index 776b440..7a9bb66 100644
--- a/tools/guest-diag/pin_gr_stream.py
+++ b/tools/guest-diag/pin_gr_stream.py
@@ -230,13 +230,24 @@ def _demand_loop():
expiry) as the stalled-VA class.
"""
track = {} # va -> [first_seen, last_sent]
+ it = 0
while True:
- time.sleep(3)
- try:
- r = subprocess.run(["sudo", "-n", "dmesg"],
- capture_output=True, text=True, timeout=20)
- except Exception:
- continue
+ # SESSION 153-CONTINUED-57: the 3 s pass was the losing half of the
+ # r1096 race - the beef setup-hold's demanded pages resolved in the
+ # guest ~2-4 s after the arm, while the pump re-read the entry
+ # every ~110 ms and moved on. Poll fast (0.75 s) so a newly armed
+ # demand goes to the guest within a second; the expensive dmesg
+ # harvest stays on a slower cadence (every 4th pass) because the
+ # debugfs setup-demand set is the time-critical source.
+ time.sleep(0.75)
+ it += 1
+ r = None
+ if it % 4 == 1:
+ try:
+ r = subprocess.run(["sudo", "-n", "dmesg"],
+ capture_output=True, text=True, timeout=20)
+ except Exception:
+ continue
now = time.time()
for m in re.finditer(
r"(?:stalled VA #\d+[:=]\s*"
@@ -258,9 +269,39 @@ def _demand_loop():
# cannot, the guest content resolver is the last source -
# harvest the VA so it resolves and injects the real page.
r"|sema-pushzero: h=0x[0-9a-f]+ va=(0x[0-9a-f]+)",
- (r.stdout or "")[-200000:]):
+ (r.stdout or "")[-2000000:] if r else ""):
va = int(m.group(1) or m.group(2) or m.group(3), 16)
track.setdefault(va, [now, 0.0])
+ # SESSION 153-CONTINUED-51: the pushzero line now carries the
+ # push length; a zero-head WINDOW push spans 1-2 pages, and the
+ # demand of a single page leaves the capture zero - expand the
+ # range and demand every page so the guest pagemap resolves the
+ # whole push at once (bulk demand instead of one page per cycle).
+ for m in re.finditer(
+ r"sema-pushzero: h=0x[0-9a-f]+ va=(0x[0-9a-f]+) len=(\d+)",
+ (r.stdout or "")[-2000000:] if r else ""):
+ zva = int(m.group(1), 16)
+ zlen = int(m.group(2))
+ for zoff in range(0, min(zlen, 0x8000), 0x1000):
+ track.setdefault(zva + zoff, [now, 0.0])
+ # SESSION 153-CONTINUED-56: the armed setup-hold's demand VA set is
+ # exposed by the service as STATE (debugfs), not as a dmesg row, so
+ # it cannot race the ring rotation under vgsp-sema spam (r1090 lost
+ # the setup-push pages that way). Read it every pass and feed the
+ # same track/resend machinery: new VAs are sent this pass (last=0),
+ # existing ones keep the 20 s resend / 300 s expiry cadence.
+ try:
+ rr = subprocess.run(
+ ["sudo", "-n", "cat",
+ "/sys/kernel/debug/vgsp/sema_setup_demand"],
+ capture_output=True, text=True, timeout=10)
+ if rr.returncode == 0:
+ for m in re.finditer(r"0x[0-9a-f]+", rr.stdout or ""):
+ sva = int(m.group(0), 16) & ~0xfff
+ if sva:
+ track.setdefault(sva, [now, 0.0])
+ except Exception:
+ pass
for va in list(track):
first, last = track[va]
if now - first > 300.0:
@@ -268,6 +309,9 @@ def _demand_loop():
todo = [va for va, (f, l) in track.items() if now - l > 20.0]
if not todo:
continue
+ # CONT-51: bound one batch's command size (a page-expanded push
+ # range can add many pages; the remainder goes next cycle).
+ todo = todo[:48]
cmd = _demand_write_cmd(todo)
try:
vexec(cmd, 30)