Commit 3a973eec by PLN (Algolia)

fix(bridge): detect resume via CLOCK_BOOTTIME, not MONOTONIC

Field-caught by the watcher itself. The laptop suspended ~10:11 and resumed
11:21:46; resume reset the pstate cap (a brief 4.4 GHz clock spike in the monitor
log), and the watcher DID restore cool — but at 11:22:04 via the ~30s periodic
drift check ("[perf-watch] drift: reasserted cool"), not the fast 2s resume path.

Cause: the resume detector used time.monotonic(), and CLOCK_MONOTONIC does not
advance while the system is suspended — so on thaw the thread saw only its normal
~5s sleep, gap << threshold, resume missed. The periodic safety net (belt-and-
suspenders) is what actually caught it.

Fix: measure the gap with CLOCK_BOOTTIME, which counts suspended time, so a resume
now shows as a large gap and triggers the immediate force-reassert (2s settle).
Falls back to monotonic if CLOCK_BOOTTIME is unavailable. Verified present on this
box (uptime read OK); watcher restarts clean with on_ac=True desired=cool.
parent e94163f1
...@@ -225,15 +225,20 @@ def run_watcher(interval=5.0, drift_every=6, log=None): ...@@ -225,15 +225,20 @@ def run_watcher(interval=5.0, drift_every=6, log=None):
cur = detect_mode() cur = detect_mode()
if cur in MODES and cur != "normal": if cur in MODES and cur != "normal":
write_desired(cur) write_desired(cur)
# BOOTTIME (not MONOTONIC) counts time spent suspended, so a resume shows up
# as a big gap here — MONOTONIC freezes across suspend and would miss it,
# leaving only the slow periodic drift check to catch a post-resume reset.
_bt = getattr(time, "CLOCK_BOOTTIME", None)
uptime = (lambda: time.clock_gettime(_bt)) if _bt is not None else time.monotonic
emit(f"watching (every {interval}s) on_ac={on_ac()} desired={read_desired()}") emit(f"watching (every {interval}s) on_ac={on_ac()} desired={read_desired()}")
last_ac = on_ac() last_ac = on_ac()
last_clock = time.monotonic() last_clock = uptime()
i = 0 i = 0
while True: while True:
time.sleep(interval) time.sleep(interval)
i += 1 i += 1
now = time.monotonic() now = uptime()
resumed = (now - last_clock) > interval * 3 # slept far longer than asked resumed = (now - last_clock) > interval * 3 # gap ≫ sleep ⇒ we were suspended
last_clock = now last_clock = now
ac = on_ac() ac = on_ac()
edge = ac is not None and last_ac is not None and ac != last_ac edge = ac is not None and last_ac is not None and ac != last_ac
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment