From 5020d33748e14cfc4c2a4a5254a07864095af49e Mon Sep 17 00:00:00 2001 From: whoisdomi Date: Fri, 29 May 2026 08:33:16 -0500 Subject: [PATCH] ui+selfdrived: pin UI after init, move selfdrived to core 5 Move the UI core-affinity pin to after MainWindow init so startup and restart recovery can use all cores (pinning before init starved the restarting UI on the contended little cores, stretching recovery from ~30s to minutes). Move selfdrived off the saturated core 4 onto core 5 so its 100 Hz loop is no longer starved, eliminating selfdrivedLagging. Verified over a full drive: selfdrivedLagging=0, core4/core5 sustained >=95% only 0.3%/1.2% of the time, UI restart recovery ~15s with the device staying engaged, radar tracking unaffected. --- selfdrive/selfdrived/selfdrived.py | 7 ++++++- selfdrive/ui/main.cc | 21 ++++++++++++--------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/selfdrive/selfdrived/selfdrived.py b/selfdrive/selfdrived/selfdrived.py index 200efa9155..1bdadf0474 100644 --- a/selfdrive/selfdrived/selfdrived.py +++ b/selfdrive/selfdrived/selfdrived.py @@ -721,7 +721,12 @@ class SelfdriveD: def main(): - config_realtime_process(4, Priority.CTRL_HIGH) + # Run on core 5 (plannerd/radard, ~50% peak, FIFO prio 51) instead of sharing + # the saturated core 4 with card+controlsd. Core 4 at 100% was starving + # selfdrived's 100 Hz loop and firing selfdrivedLagging. selfdrived's higher + # FIFO prio (53 > 51) lets it preempt the 20 Hz planner/radar when needed. + # (Core 6 = camerad, core 7 = modeld are both timing-critical — avoid.) + config_realtime_process(5, Priority.CTRL_HIGH) s = SelfdriveD() s.run() diff --git a/selfdrive/ui/main.cc b/selfdrive/ui/main.cc index 35ee73528f..9c11032116 100644 --- a/selfdrive/ui/main.cc +++ b/selfdrive/ui/main.cc @@ -31,15 +31,6 @@ void waylandAwareMessageHandler(QtMsgType type, const QMessageLogContext &contex int main(int argc, char *argv[]) { setpriority(PRIO_PROCESS, 0, -20); - // Pin the UI to the little cores (0-3). The realtime control loop - // (card/controlsd/selfdrived) runs SCHED_FIFO on core 4; without this pin the - // kernel can schedule the UI there, and a UI stall/restart spike preempts - // selfdrived, starving its 100 Hz loop and firing the "System Lagging" alert. - // Set before any threads spawn so children inherit the affinity. - if (!Hardware::PC()) { - util::set_core_affinity({0, 1, 2, 3}); - } - qInstallMessageHandler(waylandAwareMessageHandler); initApp(argc, argv); @@ -55,5 +46,17 @@ int main(int argc, char *argv[]) { MainWindow w; setMainWindow(&w); a.installEventFilter(&w); + + // Pin the UI to the little cores (0-3) AFTER startup. The realtime control + // loop (card/controlsd) runs SCHED_FIFO on core 4; this keeps the steady-state + // UI off it so a UI stall can't preempt the control loop. Deliberately done + // after MainWindow init so startup — and crucially restart recovery — can use + // all cores; pinning before init starved the restarting UI on the contended + // little cores and stretched recovery from ~30s to minutes. The per-second + // reaffine in UIState::update keeps it pinned thereafter. + if (!Hardware::PC()) { + util::set_core_affinity({0, 1, 2, 3}); + } + return a.exec(); }