fix(perf): recorder review fixes -- period adoption, timed frames, snapshot copy, watchdog stop

From review (CodeRabbit):

- The first refresh period is adopted only once two windows in a row agree.
  One loaded startup window, most frames a refresh late, used to fix a
  period twice the real one for the life of the process.
- totals.timed_frames counts the frames judged against a known period, and
  frame_soak rates late and early frames over it. Before, frames seen before
  any period was known counted as on time, so a short run could PASS
  having judged nothing; now it has no verdict.
- snapshot() copies totals. render_bench kept the snapshot object and
  differenced it against a later one sharing the same live dict, so every
  graded run reported zero frames.
- held_refresh_hz uses the p50 bucket's midpoint, not its upper edge (a
  1-2% low bias, the size of the idle-vs-held gap it exists to show).
- StallWatchdog.stop() and FrameTimingRecorder.close(); DisplayManager's
  cleanup() calls it, so the watchdog no longer outlives its manager.
- A stall that outlasts the 2s scroll-state expiry still gets its end
  reported (tracking is dropped only past GAP_SECONDS).
- test: EMULATOR through monkeypatch; docs: the 1s resume rule.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-09-24 18:33:34 -04:00
co-authored by Claude Opus 5.5
parent ffdd0efd43
commit 37203e635c
5 changed files with 169 additions and 27 deletions
+2
View File
@@ -1282,6 +1282,8 @@ class DisplayManager:
def cleanup(self):
"""Clean up resources."""
if getattr(self, 'frame_timing', None) is not None:
self.frame_timing.close()
if hasattr(self, 'matrix') and self.matrix is not None:
try:
self.matrix.Clear()