Repository navigation
A single LVGL repaint costs 40 ms against a 25 ms service period, on the task that also polls the receiver #213
Description
Measured
On hardware, main at 3f314e9, G-ONLY on screen, device untouched. Instrumentation that timed lv_timer_handler() in panel_esp.cpp's lvgl_task reported, in steady state:
draw: 11745 calls in 10025 ms, 152 redraws (151 per 10 s), mean 380 us, worst 40604 us (25000 us service period, worst 162%)
draw: 23618 calls in 10028 ms, 148 redraws (147 per 10 s), mean 170 us, worst 38532 us (25000 us service period, worst 154%)
draw: 11667 calls in 10025 ms, 152 redraws (151 per 10 s), mean 396 us, worst 41095 us (25000 us service period, worst 164%)
A repaint takes 38.5–41.1 ms. The service period on that task is 25 ms. It happens roughly 150 times per 10 seconds, so about a 60% duty cycle spent drawing.
The mean is low because most handler calls find nothing dirty and return in microseconds. The separation is stark — no-op calls are single digits, a repaint is tens of thousands — so these are not averages hiding a tail, they are two distinct populations.
Why it matters
lvgl_task dispatches the UI service callback and the GNSS poll, in that order, before each lv_timer_handler():
if (now_us - last_service_us >= kServicePeriodUs) {
last_service_us = now_us;
service_callback();
}
delay_ms = lv_timer_handler();So a 40 ms repaint pushes the next service dispatch 40 ms late. At 25 Hz a fix is due every 40 ms. The margin is gone.
The codebase already says this is the wrong arrangement, in screen_router.cpp:596:
Polled from the LVGL service tick for now, which is deliberately the arrangement most exposed to the failure the gap counter exists to catch: this is the task that has starved twice (#133, #141). That makes it a good place to watch the counter work on real hardware, and the wrong place to leave it — the receiver belongs on its own task before any vehicle testing, which is part of what #18 still has open.
This issue is the measurement behind that comment. The arrangement is not merely theoretically exposed; the drawing genuinely overruns the period by 60%.
What is measured and what is not
Measured: the repaint duration, its frequency, the task structure, and that the trace's cost grows faster than linearly in the number of trail dots — raising kImuTrailCapacity from 24 to 60 took the worst repaint from ~40 ms to ~54 ms and the object work from ~5.6 ms to ~16.5 ms (#211, reverted by #212).
Not measured, and deliberately not asserted:
- What area is actually being invalidated. 40 ms is consistent with a near-full-screen repaint of a 600x450 panel through a 96,000-byte stripe buffer, but I have not confirmed the area. 26 scattered small objects may be joining into one large region, or the invalid-area list may be saturating and marking the screen dirty wholesale. These have different fixes, so the area needs instrumenting before anything is rewritten.
- Whether fixes are actually being lost.
GnssPipelinealready countsgap_eventsandmissed_fixes, but neither is in the periodic log line, so a boot capture cannot answer it. The observed rate did dip to 22.7 Hz in one 10-second window against a configured 25, which is suggestive and not conclusive.
Suggested order
- Put
gap_eventsandmissed_fixesin the GNSS log line. Cheapest possible step, and it converts "there is no margin" into "fixes are / are not being lost". Everything below is sized differently depending on that answer. - Instrument the invalidated area so the 40 ms is attributed rather than guessed.
- Then fix the cause. Candidates, in rough order of appeal:
- Draw the trace as a single object — an
lv_canvasor a polyline — rather than 24 individually positioned dots. One invalidation instead of 24, and it is also the thing standing between Build a radar-style G meter as the G-Only primary display #136 and a longer trace. - Move the receiver poll off this task, which Build the GNSS task pipeline, queues, metrics, and 30-minute acceptance test #18 already carries and which the comment above says is needed before vehicle testing regardless.
- Reduce repaint frequency. 150 per 10 seconds is more than the 20 Hz display cadence should produce, which is itself worth understanding.
- Draw the trace as a single object — an
Notes
Pre-existing: present at the current 24-point trail, not introduced by any recent change. Found while measuring #136, which is now blocked on it — the trace cannot grow until the drawing is cheaper.
All bench work. No circuit or road test required.
Activity
fix(ui): report the receiver as it is now, not as it was at boot (#218)
feat(ui): give Race its own screen, with the lap times it was computi…
fix(ui): make Race's running-screen rule testable and drop the delta …