Skip to content

MicroPython: LVGL asserts cost 44 KB less flash - #19

Merged
bdbarnett merged 1 commit into
mainfrom
smaller-assert-handler
Nov 10, 2026
Merged

bdbarnett merged 1 commit into
mainfrom
smaller-assert-handler

Conversation

@bdbarnett

Copy link
Copy Markdown
Contributor

The assert handler from #13 made every LVGL assert site pass the full source path, the line and the function name, after testing that the weak handler exists. LVGL has about 1,230 of those sites in an ESP32-S3 build, so the firmware grew by 50.8 KB: 23 KB of code, 20 KB of function names and 6 KB of paths. On a board built with CONFIG_SPIRAM_XIP_FROM_PSRAM, ESP-IDF copies code and constants into PSRAM in 64 KB pages, and the growth pushed both over a page boundary, which took 128 KB from the heap (#10).

Now each site passes only the file's base name (__FILE_NAME__, falling back to __FILE__ on a compiler without it) and the line, to a handler declared noreturn, so a site is a load, a move and a call. File and line are enough to find the assert. The message becomes RuntimeError: LVGL assert failed at lv_display.c:614. Every MicroPython build links the handler (micropython.cmake and micropython.mk both list it), so it no longer needs to be weak. CircuitPython and CPython builds are unchanged.

Built for ESP32_GENERIC_S3 (SPIRAM_OCT, ESP-IDF 5.5.4) with only the LVGL module, the firmware is 6.3 KB larger than v9.5.53 instead of 50.8 KB, and code and constants stay in v9.5.53's 30 + 10 pages. __FILE_NAME__ is defined by every compiler we checked: GCC 13 (unix), arm-none-eabi 14.2, xtensa and riscv32 esp 14.2, mingw 13 and emscripten's clang. On a unix build the new smoke test calls set_tile_cnt(256), gets the RuntimeError with the file and line, and goes on to create a label and refresh; against the previous handler it fails on the message. pytest tests ports/micropython/tests ports/circuitpython/tests and scripts/verify_bindings.sh pass. Not run on a board.

The assert handler from #13 passed the full source path, the line and the
function name, and each of LVGL's ~1,230 assert sites tested the weak
handler before calling it. On an ESP32-S3 that added 50.8 KB to the
firmware (23 KB of code, 20 KB of function names, 6 KB of paths). With
CONFIG_SPIRAM_XIP_FROM_PSRAM, where ESP-IDF copies code and constants into
PSRAM in 64 KB pages, it pushed both over a page boundary and took 128 KB
from the heap.

Now each site passes the file's base name (__FILE_NAME__, or __FILE__ on a
compiler without it) and the line to a noreturn handler: a load, a move
and a call. The message is "LVGL assert failed at lv_display.c:614". Built
for ESP32_GENERIC_S3, the growth over v9.5.53 is 6.3 KB and stays within
the same pages.

The smoke test triggers an assert (set_tile_cnt(256)) on MicroPython,
checks the message and that LVGL keeps working; it fails against the
previous handler.
@bdbarnett
bdbarnett merged commit 665dec5 into main Nov 10, 2026
5 checks passed
@bdbarnett
bdbarnett deleted the smaller-assert-handler branch November 10, 2026 22:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant