Repository navigation
ESP32 size: −34.7 KB, below the last release again - #567
Conversation
Main had grown +15,952 B of firmware since v2026.10.15. The C side of that is feature code; five things on the Nim side were redundant, and none of the changes alters behaviour: - redactedUrl existed in Nim (1,570 B) and in C (fos_netguard_url_origin), which the firmware links anyway. On frameosEmbedded the Nim proc calls the C one; the Nim test cases pass against it (built on the host with -d:frameosEmbedded and fos_netguard.c). - A string slice `s[a .. b]` is a generic instantiated anew, ~350 B, in every module that uses one. redactedUrlsIn and httpHostOf use substr. httpHostOf is now redactedUrl without the scheme, so a URL it cannot parse reads "(invalid URL)" instead of the whole URL. - The JS preludes shipped their indentation and comments. compactJs (burrito.nim, compile time) trims each line and drops blank and `//` lines, and refuses a template literal or a trailing backslash, the two ways a string could run across lines. The asset and stream calls of `frameos` share three helpers; console points at frameos.log and frameos.error (with a test of its own, outside the test harness). - The status screen's SVG opened with a 330-byte comment, cut at compile time. - input_state.button looked up atMs, durationMs and level twice each. esp32-s3: 3,154,224 → 3,149,264 B. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…29,760 B)
Nim emits every {.inline.} proc a module needs as `static N_INLINE` into
that module's C file, and wherever GCC does not inline a call the file
keeps a private copy: 70 appendStrings, 44 nimDecRefIsLastCyclicDyns, 31
eqStrings, a dozen of each string slice's `[]`, about 21.6 KB of identical
code.
embedded/esp32/tools/fold_nim_inlines.py, run by build_nim.sh, uses C99
inline semantics: a helper defined identically in every file becomes a
plain `inline` definition (still inlinable, no private copy) everywhere
but one file, whose `extern inline` is the single external definition.
Bodies are compared after renaming the temporaries each declares (Nim
names them after the module); one that reads module data, or has a static
local, stays as it was. 199 helpers fold, 23 stay.
`weak` folds the copies too, but GCC never inlines a weak function and
that cost more than it saved (+1,392 B net, measured).
Checked: seven host suites (interpreter, dispatcher fixtures, single-scene
host, JS app runtime, all 19 repo app suites) built through the same fold
at -O0, where every call goes to the one copy, pass;
test_esp32_fold_nim_inlines.py pins the rewrite and links and runs a
folded sample at -O0 and -O2; the QEMU smoke boots it as far as it boots
main. Not yet run on hardware.
esp32-s3: 3,149,264 → 3,119,504 B, 18,768 B under v2026.10.15. The audit
of what went in since that release and both passes are in
docs/esp32-image-size.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ESP32 firmware sizeBuilt from 36ca24f by this run; compared with the latest release v2026.10.15.
Breakdown by subsystem —
|
| Subsystem | This PR | v2026.10.15 | Δ |
|---|---|---|---|
| FrameOS core (Nim) | 475,930 | 477,042 | -1,112 (-0.2%) |
| QuickJS | 360,285 | 360,373 | -88 (-0.0%) |
| pixie | 296,959 | 304,354 | -7,395 (-2.4%) |
| Wi-Fi stack | 295,296 | 295,304 | -8 (-0.0%) |
| Nim stdlib | 247,612 | 251,436 | -3,824 (-1.5%) |
| FrameOS apps (Nim) | 181,348 | 190,356 | -9,008 (-4.7%) |
| ESP-IDF misc | 181,343 | 181,564 | -221 (-0.1%) |
| Embedded font | 146,358 | 146,362 | -4 (-0.0%) |
| String pool (attributed to efuse) | 136,729 | 136,134 | +595 (+0.4%) |
| fos_* firmware shell (C) | 136,501 | 132,233 | +4,268 (+3.2%) |
| mbedTLS + certificates | 132,427 | 132,439 | -12 (-0.0%) |
| lwIP / HTTP / WebSocket | 126,939 | 126,800 | +139 (+0.1%) |
| libc / libm / newlib | 116,263 | 116,263 | ±0 |
| Storage (SPIFFS / FatFS / SD / NVS) | 94,068 | 94,080 | -12 (-0.0%) |
| Nim packages (chrono, zippy, chroma, qrgen, ...) | 70,320 | 71,849 | -1,529 (-2.1%) |
| Display drivers (C) | 64,962 | 64,946 | +16 (+0.0%) |
| Crypto (monocypher) | 35,141 | 35,141 | ±0 |
| Total mapped flash | 3,098,481 | 3,116,676 | -18,195 (-0.6%) |
Inside each subsystem
FrameOS core (Nim) — 475,930
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
frameos/js_runtime |
115,612 | 115,444 | +168 (+0.1%) |
frameos/utils |
110,853 | 112,401 | -1,548 (-1.4%) |
frameos/interpreter.nim |
100,659 | 100,264 | +395 (+0.4%) |
embedded_main.nim |
19,120 | 19,252 | -132 (-0.7%) |
embedded_runtime.nim |
17,593 | 17,834 | -241 (-1.4%) |
lib/tz.nim |
16,589 | 16,722 | -133 (-0.8%) |
frameos_nim_glue.c.obj |
11,455 | 10,635 | +820 (+7.7%) |
frameos/planner.nim |
9,574 | 9,681 | -107 (-1.1%) |
frameos/event_loop.nim |
8,143 | 8,412 | -269 (-3.2%) |
frameos/types.nim |
7,715 | 7,909 | -194 (-2.5%) |
frameos/values.nim |
7,528 | 7,699 | -171 (-2.2%) |
frameos/single_scene_host.nim |
6,379 | 6,712 | -333 (-5.0%) |
frameos/apps.nim |
6,431 | 6,585 | -154 (-2.3%) |
frameos/spool.nim |
5,560 | 5,787 | -227 (-3.9%) |
embedded_scene.nim |
4,654 | 4,945 | -291 (-5.9%) |
frameos/input_state.nim |
4,676 | 3,766 | +910 (+24.2%) |
frameos/events_gen.nim |
3,967 | 3,948 | +19 (+0.5%) |
fos_netguard.c.obj |
3,532 | 2,179 | +1,353 (+62.1%) |
frameos/app_config.nim |
2,734 | 2,935 | -201 (-6.8%) |
frameos/reboot_reason.nim |
2,332 | 2,648 | -316 (-11.9%) |
frameos/node_config.nim |
2,582 | 2,618 | -36 (-1.4%) |
frameos/app_capabilities.nim |
2,473 | 2,489 | -16 (-0.6%) |
frameos/events.nim |
2,335 | 2,410 | -75 (-3.1%) |
frameos/refresh_interval.nim |
1,593 | 1,639 | -46 (-2.8%) |
frameos/runtime_diagnostics.nim |
775 | 767 | +8 (+1.0%) |
frameos/event_log.nim |
407 | 431 | -24 (-5.6%) |
fos_version.c.obj |
328 | 328 | ±0 |
frameos/cloud |
— | 255 | -255 (-100.0%) |
frameos/channels.nim |
153 | 152 | +1 (+0.7%) |
frameos/ids.nim |
120 | 137 | -17 (-12.4%) |
frameos/hal |
44 | 44 | ±0 |
frameos/retired_apps.nim |
14 | 14 | ±0 |
QuickJS — 360,285
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
quickjs.c.obj |
287,746 | 287,846 | -100 (-0.0%) |
libunicode.c.obj |
50,178 | 50,178 | ±0 |
libregexp.c.obj |
14,007 | 13,999 | +8 (+0.1%) |
dtoa.c.obj |
5,689 | 5,685 | +4 (+0.1%) |
cutils.c.obj |
2,141 | 2,141 | ±0 |
fos_qjs_glue.c.obj |
449 | 449 | ±0 |
fos_quickjs_tz.c.obj |
75 | 75 | ±0 |
pixie — 296,959
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
pixie/fontformats/opentype.nim |
56,066 | 55,460 | +606 (+1.1%) |
pixie/fileformats/webp.nim |
36,937 | 37,493 | -556 (-1.5%) |
pixie/fileformats/svg.nim |
35,546 | 36,983 | -1,437 (-3.9%) |
pixie/paths.nim |
31,616 | 32,875 | -1,259 (-3.8%) |
pixie/fileformats/jpeg.nim |
29,164 | 29,436 | -272 (-0.9%) |
pixie/fileformats/png.nim |
21,475 | 22,101 | -626 (-2.8%) |
pixie/images.nim |
15,445 | 15,779 | -334 (-2.1%) |
pixie/fonts.nim |
10,301 | 10,995 | -694 (-6.3%) |
pixie/paints.nim |
9,023 | 9,869 | -846 (-8.6%) |
pixie/fileformats/bmp.nim |
7,612 | 8,258 | -646 (-7.8%) |
pixie/common.nim |
7,158 | 7,413 | -255 (-3.4%) |
pixie/blends.nim |
6,622 | 6,516 | +106 (+1.6%) |
pixie/fileformats/gif.nim |
5,737 | 5,965 | -228 (-3.8%) |
pixie.nim |
5,243 | 5,224 | +19 (+0.4%) |
pixie/inflatestream.nim |
5,156 | 5,233 | -77 (-1.5%) |
pixie/fileformats/webp_vp8_tables.nim |
3,881 | 3,881 | ±0 |
pixie/fileformats/ppm.nim |
3,520 | 3,713 | -193 (-5.2%) |
pixie/contexts.nim |
2,951 | 3,054 | -103 (-3.4%) |
pixie/fileformats/qoi.nim |
2,437 | 2,702 | -265 (-9.8%) |
pixie/internal.nim |
502 | 754 | -252 (-33.4%) |
pixie/rgb565.nim |
327 | 385 | -58 (-15.1%) |
pixie/fontformats/svgfont.nim |
190 | 215 | -25 (-11.6%) |
pixie/decodebudget.nim |
50 | 50 | ±0 |
Wi-Fi stack — 295,296
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
libnet80211.a |
136,148 | 136,168 | -20 (-0.0%) |
libpp.a |
62,158 | 62,154 | +4 (+0.0%) |
libwpa_supplicant.a |
54,904 | 54,904 | ±0 |
libphy.a |
34,176 | 34,176 | ±0 |
libesp_wifi.a |
4,788 | 4,780 | +8 (+0.2%) |
libesp_phy.a |
2,541 | 2,541 | ±0 |
libesp_coex.a |
291 | 291 | ±0 |
libcore.a |
287 | 287 | ±0 |
libespnow.a |
3 | 3 | ±0 |
Nim stdlib — 247,612
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
pure/collections/tables.nim |
72,114 | 72,312 | -198 (-0.3%) |
system.nim |
48,163 | 48,457 | -294 (-0.6%) |
pure/unicode.nim |
17,324 | 17,405 | -81 (-0.5%) |
pure/times.nim |
16,493 | 16,888 | -395 (-2.3%) |
pure/json.nim |
13,478 | 13,722 | -244 (-1.8%) |
std/private/dragonbox.nim |
10,348 | 10,351 | -3 (-0.0%) |
pure/strutils.nim |
7,847 | 8,047 | -200 (-2.5%) |
pure/parsexml.nim |
5,802 | 6,011 | -209 (-3.5%) |
pure/algorithm.nim |
5,324 | 5,372 | -48 (-0.9%) |
pure/base64.nim |
5,107 | 5,290 | -183 (-3.5%) |
pure/hashes.nim |
4,003 | 4,181 | -178 (-4.3%) |
pure/xmlparser.nim |
3,407 | 3,555 | -148 (-4.2%) |
pure/parsejson.nim |
3,392 | 3,553 | -161 (-4.5%) |
std/formatfloat.nim |
3,476 | 3,504 | -28 (-0.8%) |
pure/uri.nim |
2,988 | 3,225 | -237 (-7.3%) |
pure/streams.nim |
2,749 | 2,820 | -71 (-2.5%) |
pure/strformat.nim |
2,380 | 2,546 | -166 (-6.5%) |
std/syncio.nim |
2,282 | 2,355 | -73 (-3.1%) |
pure/collections/sets.nim |
2,089 | 2,075 | +14 (+0.7%) |
pure/xmltree.nim |
1,862 | 2,047 | -185 (-9.0%) |
pure/lexbase.nim |
1,775 | 1,801 | -26 (-1.4%) |
pure/parseutils.nim |
1,741 | 1,750 | -9 (-0.5%) |
system/exceptions.nim |
1,530 | 1,598 | -68 (-4.3%) |
pure/strtabs.nim |
1,507 | 1,572 | -65 (-4.1%) |
pure/pathnorm.nim |
1,212 | 1,336 | -124 (-9.3%) |
pure/options.nim |
815 | 1,016 | -201 (-19.8%) |
std/private/ospaths2.nim |
966 | 994 | -28 (-2.8%) |
pure/collections/lists.nim |
990 | 979 | +11 (+1.1%) |
pure/collections/deques.nim |
844 | 822 | +22 (+2.7%) |
pure/math.nim |
839 | 841 | -2 (-0.2%) |
pure/random.nim |
688 | 696 | -8 (-1.1%) |
std/private/digitsutils.nim |
617 | 651 | -34 (-5.2%) |
std/oserrors.nim |
489 | 633 | -144 (-22.7%) |
std/private/osdirs.nim |
510 | 572 | -62 (-10.8%) |
system/dollars.nim |
431 | 529 | -98 (-18.5%) |
std/monotimes.nim |
485 | 406 | +79 (+19.5%) |
std/private/oscommon.nim |
325 | 329 | -4 (-1.2%) |
std/envvars.nim |
310 | 250 | +60 (+24.0%) |
std/private/decode_helpers.nim |
181 | 240 | -59 (-24.6%) |
std/private/ossymlinks.nim |
187 | 187 | ±0 |
pure/bitops.nim |
162 | 162 | ±0 |
pure/os.nim |
99 | 99 | ±0 |
std/private/osfiles.nim |
96 | 96 | ±0 |
core/macros.nim |
89 | 65 | +24 (+36.9%) |
std/assertions.nim |
87 | 87 | ±0 |
system/ctypes.nim |
9 | 9 | ±0 |
FrameOS apps (Nim) — 181,348
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
apps/data/icalJson |
50,262 | 50,733 | -471 (-0.9%) |
apps/render/calendar |
29,944 | 30,874 | -930 (-3.0%) |
apps/data/localImage |
10,340 | 10,432 | -92 (-0.9%) |
apps/render/split |
9,389 | 9,772 | -383 (-3.9%) |
apps/data/eventsToAgenda |
8,568 | 9,068 | -500 (-5.5%) |
apps/render/zoomPan |
8,360 | 8,648 | -288 (-3.3%) |
apps/apps.nim |
7,208 | 7,247 | -39 (-0.5%) |
apps/render/text |
5,234 | 5,455 | -221 (-4.1%) |
apps/data/xmlToJson |
5,190 | 5,428 | -238 (-4.4%) |
apps/render/svg |
4,583 | 5,192 | -609 (-11.7%) |
apps/render/image |
4,423 | 4,708 | -285 (-6.1%) |
apps/data/rotateImage |
2,939 | 3,465 | -526 (-15.2%) |
apps/logic/setAsState |
3,181 | 3,453 | -272 (-7.9%) |
apps/data/downloadImage |
3,128 | 3,325 | -197 (-5.9%) |
apps/render/gradient |
2,983 | 3,229 | -246 (-7.6%) |
apps/data/qr |
3,017 | 3,122 | -105 (-3.4%) |
apps/data/downloadUrl |
2,774 | 3,053 | -279 (-9.1%) |
apps/render/color |
2,059 | 2,824 | -765 (-27.1%) |
apps/data/newImage |
2,175 | 2,668 | -493 (-18.5%) |
apps/data/resizeImage |
2,312 | 2,558 | -246 (-9.6%) |
apps/data/log |
2,053 | 2,299 | -246 (-10.7%) |
apps/render/opacity |
2,055 | 2,296 | -241 (-10.5%) |
apps/data/prettyJson |
1,947 | 2,225 | -278 (-12.5%) |
apps/data/clock |
1,718 | 1,875 | -157 (-8.4%) |
apps/data/parseJson |
1,585 | 1,856 | -271 (-14.6%) |
apps/logic/nextSleepDuration |
1,394 | 1,663 | -269 (-16.2%) |
apps/logic/ifElse |
1,311 | 1,494 | -183 (-12.2%) |
apps/logic/breakIfRendering |
1,216 | 1,394 | -178 (-12.8%) |
ESP-IDF misc — 181,343
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
libesp_hw_support.a |
37,620 | 37,632 | -12 (-0.0%) |
libhal.a |
21,865 | 21,865 | ±0 |
libfreertos.a |
17,240 | 17,240 | ±0 |
libesp_system.a |
13,736 | 13,780 | -44 (-0.3%) |
libesp_driver_uart.a |
11,627 | 11,627 | ±0 |
libheap.a |
8,660 | 8,660 | ±0 |
libesp_driver_i2c.a |
8,062 | 8,062 | ±0 |
libesp_driver_spi.a |
7,760 | 7,756 | +4 (+0.1%) |
libconsole.a |
5,733 | 5,733 | ±0 |
libjson.a |
4,940 | 4,940 | ±0 |
libesp_driver_gpio.a |
3,878 | 3,878 | ±0 |
libbootloader_support.a |
3,813 | 3,813 | ±0 |
libxtensa.a |
3,691 | 3,691 | ±0 |
libesp_driver_usb_serial_jtag.a |
3,408 | 3,408 | ±0 |
libesp_ringbuf.a |
3,322 | 3,322 | ±0 |
libesp_event.a |
3,241 | 3,253 | -12 (-0.4%) |
libesp_driver_ledc.a |
3,054 | 3,054 | ±0 |
libesp_mm.a |
2,451 | 2,451 | ±0 |
libapp_update.a |
2,414 | 2,414 | ±0 |
libesp_timer.a |
2,337 | 2,337 | ±0 |
libesp_psram.a |
2,172 | 2,329 | -157 (-6.7%) |
libsoc.a |
2,316 | 2,316 | ±0 |
libesp_adc.a |
2,285 | 2,285 | ±0 |
libpthread.a |
1,397 | 1,397 | ±0 |
liblog.a |
1,375 | 1,375 | ±0 |
libesp_security.a |
1,050 | 1,050 | ±0 |
libesp_rom.a |
902 | 902 | ±0 |
libesp_app_format.a |
507 | 507 | ±0 |
libxt_hal.a |
437 | 437 | ±0 |
libesp_common.a |
26 | 26 | ±0 |
libesp_pm.a |
24 | 24 | ±0 |
Embedded font — 146,358
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
assets/fonts.nim |
146,358 | 146,362 | -4 (-0.0%) |
String pool (attributed to efuse) — 136,729
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
esp_efuse_utility.c.obj |
135,683 | 135,088 | +595 (+0.4%) |
esp_efuse_rtc_calib.c.obj |
566 | 566 | ±0 |
esp_efuse_table.c.obj |
268 | 268 | ±0 |
esp_efuse_api.c.obj |
151 | 151 | ±0 |
esp_efuse_startup.c.obj |
61 | 61 | ±0 |
fos_ firmware shell (C)* — 136,501
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
fos_http.c.obj |
22,185 | 22,185 | ±0 |
fos_cloud.c.obj |
19,651 | 19,258 | +393 (+2.0%) |
fos_console.c.obj |
14,001 | 13,950 | +51 (+0.4%) |
fos_client.c.obj |
12,957 | 12,266 | +691 (+5.6%) |
fos_settings.c.obj |
7,722 | 7,618 | +104 (+1.4%) |
fos_scenes.c.obj |
7,515 | 7,578 | -63 (-0.8%) |
fos_ota.c.obj |
5,639 | 5,467 | +172 (+3.1%) |
fos_cloud_contract.c.obj |
4,768 | 4,744 | +24 (+0.5%) |
fos_config.c.obj |
4,619 | 4,619 | ±0 |
fos_wifi.c.obj |
3,189 | 3,189 | ±0 |
fos_assets.c.obj |
3,124 | 3,124 | ±0 |
fos_sd_probe.c.obj |
2,753 | 2,753 | ±0 |
fos_buttons.c.obj |
2,737 | 2,493 | +244 (+9.8%) |
fos_schedule.c.obj |
2,614 | 2,602 | +12 (+0.5%) |
fos_assets_sd.c.obj |
2,484 | 2,484 | ±0 |
fos_events.c.obj |
2,332 | 2,320 | +12 (+0.5%) |
fos_panel_draw.c.obj |
2,229 | — | +2,229 |
fos_status_screen.c.obj |
893 | 2,049 | -1,156 (-56.4%) |
main.c.obj |
1,703 | 1,699 | +4 (+0.2%) |
fos_config_parse.c.obj |
1,467 | 1,467 | ±0 |
fos_url_guard.c.obj |
1,397 | 1,397 | ±0 |
fos_tz.c.obj |
1,294 | 1,294 | ±0 |
fos_buzzer.c.obj |
1,162 | 901 | +261 (+29.0%) |
fos_battery.c.obj |
1,140 | 1,140 | ±0 |
fos_minisig.c.obj |
1,140 | 1,140 | ±0 |
fos_backend_http.c.obj |
1,072 | 1,072 | ±0 |
fos_commands.c.obj |
940 | 940 | ±0 |
fos_lan_access.c.obj |
841 | — | +841 |
fos_scene_state.c.obj |
650 | 650 | ±0 |
fos_framebuffer.c.obj |
483 | 483 | ±0 |
fos_button_timing.c.obj |
434 | — | +434 |
fos_board.c.obj |
334 | 334 | ±0 |
fos_assets_path.c.obj |
259 | 259 | ±0 |
fos_power.c.obj |
241 | 241 | ±0 |
fos_battery_filter.c.obj |
214 | 214 | ±0 |
fos_wake.c.obj |
199 | 184 | +15 (+8.2%) |
fos_json_guard.c.obj |
119 | 119 | ±0 |
mbedTLS + certificates — 132,427
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
libmbedcrypto.a |
71,291 | 71,291 | ±0 |
libmbedtls.a |
45,799 | 45,799 | ±0 |
libmbedx509.a |
7,080 | 7,092 | -12 (-0.2%) |
libesp-tls.a |
6,705 | 6,705 | ±0 |
libesp_https_server.a |
1,552 | 1,552 | ±0 |
lwIP / HTTP / WebSocket — 126,939
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
liblwip.a |
78,529 | 78,445 | +84 (+0.1%) |
libhttp_parser.a |
10,350 | 10,350 | ±0 |
libesp_http_server.a |
10,020 | 10,020 | ±0 |
libtcp_transport.a |
8,245 | 8,245 | ±0 |
libespressif__esp_websocket_client.a |
6,822 | 6,822 | ±0 |
libesp_http_client.a |
6,666 | 6,666 | ±0 |
libesp_netif.a |
6,307 | 6,252 | +55 (+0.9%) |
libc / libm / newlib — 116,263
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
libc.a |
76,471 | 76,471 | ±0 |
libm.a |
31,563 | 31,563 | ±0 |
libnewlib.a |
6,609 | 6,609 | ±0 |
libstdc++.a |
1,476 | 1,476 | ±0 |
libgcc.a |
98 | 98 | ±0 |
libcxx.a |
46 | 46 | ±0 |
Storage (SPIFFS / FatFS / SD / NVS) — 94,068
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
libspiffs.a |
20,380 | 20,380 | ±0 |
libfatfs.a |
20,141 | 20,133 | +8 (+0.0%) |
libspi_flash.a |
14,168 | 14,168 | ±0 |
libnvs_flash.a |
13,665 | 13,685 | -20 (-0.1%) |
libsdmmc.a |
13,013 | 13,013 | ±0 |
libvfs.a |
6,196 | 6,196 | ±0 |
libesp_driver_sdspi.a |
3,866 | 3,866 | ±0 |
libesp_partition.a |
1,956 | 1,956 | ±0 |
libesp_vfs_console.a |
678 | 678 | ±0 |
libnvs_sec_provider.a |
5 | 5 | ±0 |
Nim packages (chrono, zippy, chroma, qrgen, ...) — 70,320
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
QRgen 3.1.0 |
21,886 | 22,060 | -174 (-0.8%) |
chrono 0.3.1 |
15,049 | 15,586 | -537 (-3.4%) |
zippy 0.10.19 |
14,936 | 15,200 | -264 (-1.7%) |
chroma 1.0.0 |
14,368 | 14,714 | -346 (-2.4%) |
checksums 0.2.1 |
3,290 | 3,371 | -81 (-2.4%) |
flatty 0.3.4 |
530 | 533 | -3 (-0.6%) |
jsony 1.1.5 |
148 | 272 | -124 (-45.6%) |
bumpy 1.1.3 |
113 | 113 | ±0 |
Display drivers (C) — 64,962
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
(everything else) |
21,278 | 21,282 | -4 (-0.0%) |
frameos_panel_table.c.obj |
6,685 | 6,685 | ±0 |
EPD_13in3e.c.obj |
1,796 | 1,796 | ±0 |
EPD_3in7.c.obj |
1,564 | 1,564 | ±0 |
EPD_5in79.c.obj |
1,481 | 1,481 | ±0 |
DEV_Debug.c.obj |
1,313 | 1,317 | -4 (-0.3%) |
EPD_2in7.c.obj |
1,292 | 1,292 | ±0 |
EPD_4in2.c.obj |
1,262 | 1,262 | ±0 |
EPD_7in3e.c.obj |
1,208 | 1,208 | ±0 |
EPD_4in2_V2.c.obj |
1,184 | 1,184 | ±0 |
DEV_Config_esp.c.obj |
1,180 | 1,180 | ±0 |
EPD_4in26.c.obj |
1,123 | 1,123 | ±0 |
| 29 smaller rows | 23,596 | 23,572 | +24 (+0.1%) |
Crypto (monocypher) — 35,141
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
monocypher.c.obj |
31,916 | 31,916 | ±0 |
monocypher-ed25519.c.obj |
3,225 | 3,225 | ±0 |
Biggest movers (per object)
| Object | Δ | This PR | Baseline |
|---|---|---|---|
frameos/input_state.nim |
+4,676 | 4,676 | — |
pkgs/QRgen-3.1.0/QRgen/renderer.nim |
-3,780 | — | 3,780 |
pkgs/pixie-6.1.0/pixie/fileformats/svg.nim |
-1,437 | 35,546 | 36,983 |
frameos/utils/status_screen.nim |
-1,392 | 16,551 | 17,943 |
pkgs/pixie-6.1.0/pixie/paths.nim |
-1,259 | 31,616 | 32,875 |
apps/render/calendar/app.nim |
-976 | 22,841 | 23,817 |
pkgs/pixie-6.1.0/pixie/paints.nim |
-846 | 9,023 | 9,869 |
frameos/utils/http_client.nim |
+821 | 10,811 | 9,990 |
frameos_nim_glue.c.obj |
+820 | 11,455 | 10,635 |
pkgs/pixie-6.1.0/pixie/fonts.nim |
-694 | 10,301 | 10,995 |
fos_client.c.obj |
+691 | 12,957 | 12,266 |
frameos/utils/image.nim |
-683 | 35,259 | 35,942 |
pkgs/pixie-6.1.0/pixie/fileformats/bmp.nim |
-646 | 7,612 | 8,258 |
pkgs/pixie-6.1.0/pixie/fileformats/png.nim |
-626 | 21,475 | 22,101 |
pkgs/pixie-6.1.0/pixie/fontformats/opentype.nim |
+606 | 56,066 | 55,460 |
Largest 30 objects
| Object | Subsystem | This PR | v2026.10.15 | Δ |
|---|---|---|---|---|
quickjs.c.obj |
QuickJS | 287,746 | 287,846 | -100 (-0.0%) |
assets/fonts.nim |
Embedded font | 146,358 | 146,362 | -4 (-0.0%) |
esp_efuse_utility.c.obj |
String pool (attributed to efuse) | 135,683 | 135,088 | +595 (+0.4%) |
frameos/interpreter.nim |
FrameOS core (Nim) | 100,659 | 100,264 | +395 (+0.4%) |
frameos/js_runtime/app_runtime.nim |
FrameOS core (Nim) | 72,782 | 72,635 | +147 (+0.2%) |
nim/lib/pure/collections/tables.nim |
Nim stdlib | 72,114 | 72,312 | -198 (-0.3%) |
pkgs/pixie-6.1.0/pixie/fontformats/opentype.nim |
pixie | 56,066 | 55,460 | +606 (+1.1%) |
libunicode.c.obj |
QuickJS | 50,178 | 50,178 | ±0 |
nim/lib/system.nim |
Nim stdlib | 48,163 | 48,457 | -294 (-0.6%) |
apps/data/icalJson/ical.nim |
FrameOS apps (Nim) | 44,746 | 45,016 | -270 (-0.6%) |
pkgs/pixie-6.1.0/pixie/fileformats/webp.nim |
pixie | 36,937 | 37,493 | -556 (-1.5%) |
pkgs/pixie-6.1.0/pixie/fileformats/svg.nim |
pixie | 35,546 | 36,983 | -1,437 (-3.9%) |
frameos/utils/image.nim |
FrameOS core (Nim) | 35,259 | 35,942 | -683 (-1.9%) |
monocypher.c.obj |
Crypto (monocypher) | 31,916 | 31,916 | ±0 |
pkgs/pixie-6.1.0/pixie/paths.nim |
pixie | 31,616 | 32,875 | -1,259 (-3.8%) |
frameos/js_runtime/runtime.nim |
FrameOS core (Nim) | 31,330 | 31,686 | -356 (-1.1%) |
pkgs/pixie-6.1.0/pixie/fileformats/jpeg.nim |
pixie | 29,164 | 29,436 | -272 (-0.9%) |
apps/render/calendar/app.nim |
FrameOS apps (Nim) | 22,841 | 23,817 | -976 (-4.1%) |
fos_http.c.obj |
fos_* firmware shell (C) | 22,185 | 22,185 | ±0 |
pkgs/pixie-6.1.0/pixie/fileformats/png.nim |
pixie | 21,475 | 22,101 | -626 (-2.8%) |
fos_cloud.c.obj |
fos_* firmware shell (C) | 19,651 | 19,258 | +393 (+2.0%) |
embedded_main.nim |
FrameOS core (Nim) | 19,120 | 19,252 | -132 (-0.7%) |
x509_crt_bundle.S.obj |
mbedTLS + certificates | 17,928 | 17,928 | ±0 |
embedded_runtime.nim |
FrameOS core (Nim) | 17,593 | 17,834 | -241 (-1.4%) |
nim/lib/pure/unicode.nim |
Nim stdlib | 17,324 | 17,405 | -81 (-0.5%) |
frameos/utils/asset_colors.nim |
FrameOS core (Nim) | 17,028 | 17,333 | -305 (-1.8%) |
lib/tz.nim |
FrameOS core (Nim) | 16,589 | 16,722 | -133 (-0.8%) |
frameos/utils/status_screen.nim |
FrameOS core (Nim) | 16,551 | 17,943 | -1,392 (-7.8%) |
nim/lib/pure/times.nim |
Nim stdlib | 16,493 | 16,888 | -395 (-2.3%) |
ieee80211_ioctl.o |
Wi-Fi stack | 15,592 | 15,588 | +4 (+0.0%) |
Flash = .text + .rodata from the linker map via esp_idf_size; "Inside each subsystem" splits every bucket one level down (the Nim core by directory, apps by app, packages by package, ESP-IDF by archive) over all objects, not just the largest. "String pool (attributed to efuse)" is the linker's merged string-literal pool for the whole image, not efuse code — see docs/esp32-image-size.md.
Main had grown +15,952 B of ESP32 firmware since v2026.10.15 (3,138,272 → 3,154,224; the release tree rebuilt locally matches the published image byte for byte). This PR takes it to 3,119,504 B: −34,720 against main, 18,768 B under the release, OTA slot 87.5% → 86.5%. The audit of what went in and both passes are written up in
docs/esp32-image-size.md.What went in since 2026.10.15
redacted_url.nim(new)fos_panel_draw.c/fos_status_screen.capp_runtime.nim(prelude literal +1,274)http_client.nimfos_netguard.cinput_state.nimfos_client.c, deadline message, buttons/buzzerThe C side is feature code. The Nim side carried duplicates.
Commit 1: what was there twice (−4,960, no behaviour change)
redactedUrlcalls the Cfos_netguard_url_origininstead of keeping a Nim twin (the Nim test cases pass against it).redactedUrlsIn/httpHostOf(each module that slices gets its own ~350 B copy).httpHostOfis nowredactedUrlminus the scheme, so an unparseable URL no longer falls back to the whole URL in the deadline message.compactJs: the JS preludes lose indentation, blank and//lines at compile time (guarded against template literals and trailing backslashes); theframeosasset/stream calls share helpers;consolepoints atframeos.log/frameos.error, with a new test.Commit 2: one copy of each Nim inline helper (−29,760)
Nim writes every inline helper into each C file that calls it (70
appendStrings, 44nimDecRefIsLastCyclicDyns, …).embedded/esp32/tools/fold_nim_inlines.py, run bybuild_nim.sh, rewrites helpers whose definition is identical in every file as C99inline, withextern inlinein one owner file. GCC still inlines where it wants; every other call goes to one copy. 199 fold, 23 that read module data stay. (weakwas tried and made it 1.4 KB bigger: GCC never inlines weak functions.)Testing
-O0, so every call hits the single copy: all pass.test_esp32_fold_nim_inlines.py: the rewrite, the cases that must not fold, and a folded sample linked and run at-O0and-O2.test_fos_netguard.c(222 checks),generate_scene_guide.py --check.ci_build_image.shin the esp32-ci image: 3,119,504 B; QEMU smoke boots as far as main does (both stop before app_main).Not done: a hardware run. The fold rewrites generated C, so this wants a bench pass on the E1002 (a render, a JS app scene, a button press) before merging.
🤖 Generated with Claude Code