diff --git a/system/ui/lib/application.py b/system/ui/lib/application.py index 76d6867514..22c6ed71f2 100644 --- a/system/ui/lib/application.py +++ b/system/ui/lib/application.py @@ -1,14 +1,21 @@ import atexit import os +import time import pyray as rl from enum import IntEnum from openpilot.common.basedir import BASEDIR +from openpilot.common.swaglog import cloudlog -DEFAULT_TEXT_SIZE = 60 DEFAULT_FPS = 60 -FONT_DIR = os.path.join(BASEDIR, "selfdrive/assets/fonts") +FPS_LOG_INTERVAL = 5 # Seconds between logging FPS drops +FPS_DROP_THRESHOLD = 0.9 # FPS drop threshold for triggering a warning +FPS_CRITICAL_THRESHOLD = 0.5 # Critical threshold for triggering strict actions DEBUG_FPS = os.getenv("DEBUG_FPS") == '1' +STRICT_MODE = os.getenv("STRICT_MODE") == '1' + +DEFAULT_TEXT_SIZE = 60 +FONT_DIR = os.path.join(BASEDIR, "selfdrive/assets/fonts") class FontWeight(IntEnum): @@ -18,7 +25,7 @@ class FontWeight(IntEnum): EXTRA_LIGHT = 3 MEDIUM = 4 NORMAL = 5 - SEMI_BOLD= 6 + SEMI_BOLD = 6 THIN = 7 @@ -28,6 +35,8 @@ class GuiApplication: self._width = width self._height = height self._textures: list[rl.Texture] = [] + self._target_fps: int = DEFAULT_FPS + self._last_fps_log_time: float = time.monotonic() def init_window(self, title: str, fps: int=DEFAULT_FPS): atexit.register(self.close) # Automatically call close() on exit @@ -36,6 +45,7 @@ class GuiApplication: rl.init_window(self._width, self._height, title) rl.set_target_fps(fps) + self._target_fps = fps self._set_styles() self._load_fonts() @@ -72,6 +82,7 @@ class GuiApplication: rl.draw_fps(10, 10) rl.end_drawing() + self._monitor_fps() def font(self, font_wight: FontWeight=FontWeight.NORMAL): return self._fonts[font_wight] @@ -111,5 +122,20 @@ class GuiApplication: rl.gui_set_style(rl.GuiControl.DEFAULT, rl.GuiDefaultProperty.BACKGROUND_COLOR, rl.color_to_int(rl.Color(30, 30, 30, 255))) rl.gui_set_style(rl.GuiControl.DEFAULT, rl.GuiControlProperty.BASE_COLOR_NORMAL, rl.color_to_int(rl.Color(50, 50, 50, 255))) + def _monitor_fps(self): + fps = rl.get_fps() + + # Log FPS drop below threshold at regular intervals + if fps < self._target_fps * FPS_DROP_THRESHOLD: + current_time = time.monotonic() + if current_time - self._last_fps_log_time >= FPS_LOG_INTERVAL: + cloudlog.warning(f"FPS dropped below {self._target_fps}: {fps}") + self._last_fps_log_time = current_time + + # Strict mode: terminate UI if FPS drops too much + if STRICT_MODE and fps < self._target_fps * FPS_CRITICAL_THRESHOLD: + cloudlog.error(f"FPS dropped critically below {fps}. Shutting down UI.") + os._exit(1) + gui_app = GuiApplication(2160, 1080)