from PyQt6.QtCore import QObject, QTimer, QElapsedTimer import logging import time from config import Config class EventLoopJitterMonitor(QObject): def __init__( self, parent=None, interval_ms: int = 20, jitter_threshold_ms: int = 100, log_cooldown_s: float = 1.0, ): super().__init__(parent) self._interval = interval_ms self._jitter_threshold = jitter_threshold_ms self._log_cooldown_s = log_cooldown_s self._timer = QTimer(self) self._timer.setInterval(self._interval) self._timer.timeout.connect(self._on_timeout) self._elapsed = QElapsedTimer() self._elapsed.start() self._last = self._elapsed.elapsed() # child logger: e.g. "musicmuster.jitter" self._log = logging.getLogger(f"{Config.LOG_NAME}.jitter") self._last_log_time = 0.0 def start(self) -> None: self._timer.start() def _on_timeout(self) -> None: now_ms = self._elapsed.elapsed() delta = now_ms - self._last self._last = now_ms if delta > (self._interval + self._jitter_threshold): self._log_jitter(now_ms, delta) def _log_jitter(self, now_ms: int, gap_ms: int) -> None: now = time.monotonic() # simple rate limit: only one log every log_cooldown_s if now - self._last_log_time < self._log_cooldown_s: return self._last_log_time = now self._log.warning( "Event loop gap detected: t=%d ms, gap=%d ms (interval=%d ms)", now_ms, gap_ms, self._interval, )