From cdd06d43395e75d7c0846d564b287349384684ed Mon Sep 17 00:00:00 2001 From: Ed_ Date: Mon, 23 Feb 2026 14:43:07 -0500 Subject: [PATCH] feat(perf): Implement Input Lag estimation logic --- gui.py | 5 +++++ performance_monitor.py | 15 ++++++++++++++- tests/test_performance_monitor.py | 10 ++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/gui.py b/gui.py index 3cf5621..d509840 100644 --- a/gui.py +++ b/gui.py @@ -1698,6 +1698,11 @@ class App: ) def _build_ui(self): + # Performance tracking handlers + with dpg.handler_registry(): + dpg.add_mouse_click_handler(callback=lambda: self.perf_monitor.record_input_event()) + dpg.add_key_press_handler(callback=lambda: self.perf_monitor.record_input_event()) + with dpg.viewport_menu_bar(): with dpg.menu(label="Windows"): for label, tag in self.window_info.items(): diff --git a/performance_monitor.py b/performance_monitor.py index e5874a5..bd0fdf9 100644 --- a/performance_monitor.py +++ b/performance_monitor.py @@ -13,6 +13,10 @@ class PerformanceMonitor: self._cpu_usage = 0.0 self._cpu_lock = threading.Lock() + # Input lag tracking + self._last_input_time = None + self._input_lag_ms = 0.0 + # Start CPU usage monitoring thread self._stop_event = threading.Event() self._cpu_thread = threading.Thread(target=self._monitor_cpu, daemon=True) @@ -29,6 +33,9 @@ class PerformanceMonitor: def start_frame(self): self._start_time = time.time() + def record_input_event(self): + self._last_input_time = time.time() + def end_frame(self): if self._start_time is None: return @@ -37,6 +44,11 @@ class PerformanceMonitor: self._last_frame_time = (end_time - self._start_time) * 1000.0 self._frame_count += 1 + # Calculate input lag if an input occurred during this frame + if self._last_input_time is not None: + self._input_lag_ms = (end_time - self._last_input_time) * 1000.0 + self._last_input_time = None + elapsed_since_fps = end_time - self._fps_last_time if elapsed_since_fps >= 1.0: self._fps = self._frame_count / elapsed_since_fps @@ -50,7 +62,8 @@ class PerformanceMonitor: return { 'last_frame_time_ms': self._last_frame_time, 'fps': self._fps, - 'cpu_percent': cpu_usage + 'cpu_percent': cpu_usage, + 'input_lag_ms': self._input_lag_ms } def stop(self): diff --git a/tests/test_performance_monitor.py b/tests/test_performance_monitor.py index 5052774..ec05193 100644 --- a/tests/test_performance_monitor.py +++ b/tests/test_performance_monitor.py @@ -23,5 +23,15 @@ class TestPerformanceMonitor(unittest.TestCase): self.assertIn('cpu_percent', metrics) self.assertIsInstance(metrics['cpu_percent'], float) + def test_input_lag_collection(self): + self.monitor.start_frame() + self.monitor.record_input_event() + time.sleep(0.02) # 20ms lag + self.monitor.end_frame() + + metrics = self.monitor.get_metrics() + self.assertGreaterEqual(metrics['input_lag_ms'], 20) + self.assertLess(metrics['input_lag_ms'], 40) + if __name__ == '__main__': unittest.main()