Repository navigation
CI: Nim test nimcache as immutable snapshots (shard 1 red on main) - #568
Conversation
…not mix it Shard 1 failed to link on three runs in a row, main included (`undefined reference to eqdup___OOZconfig_u2307` in test_runner_loop, `eqdup___OOZjs95runtimeZapp95runtime_*` in test_refresh_interval), with no code at fault. Nim reuses a module's object file when the C it generates equals the .c on disk and the .o is newer (shouldRecompile in compiler/cgen.nim); nothing checks that the .o came from that .c. The warm cache was one shared directory per shard that overlapping runs copied into (rsync) and out of (cp -a) at the same time, so a restore could take one build's .c and another build's newer .o. Nim linked the stale object, and the save after it wrote the pair back for every later run. frameos/tools/ci_nimcache.sh keeps each shard's cache as snapshots written once and never changed. A save rsyncs into a new snapshot with --link-dest on the snapshot the job restored (unchanged files become hardlinks, so a save costs only what the run rebuilt), then swaps a `current` symlink in one rename. A restore resolves the symlink once and copies that snapshot. Replaced snapshots live 30 minutes for restores still copying. Hardlinks follow rsync's size + mtime check, so they come only from the job's own restored snapshot, which every file the job wrote is newer than. The cache moves to a new path, which also drops the poisoned pairs. The save is skipped on a cancelled job: a gcc killed mid-write leaves a truncated .o newer than its .c. Stress-tested in a Linux container: three savers doing restore, rebuild, save cycles against four restorers for 30 s, 227 restores, none with a test dir mixing two builds. The old scheme under the same load: 250 of 266 restores mixed, and the shared directory itself ended up holding a mixed test dir, the pair every later run would have linked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ESP32 firmware sizeBuilt from cbf8647 by this run; compared with the latest release v2026.10.15.
Breakdown by subsystem —
|
| Subsystem | This PR | v2026.10.15 | Δ |
|---|---|---|---|
| FrameOS core (Nim) | 487,875 | 477,042 | +10,833 (+2.3%) |
| QuickJS | 360,345 | 360,373 | -28 (-0.0%) |
| pixie | 304,382 | 304,354 | +28 (+0.0%) |
| Wi-Fi stack | 295,296 | 295,304 | -8 (-0.0%) |
| Nim stdlib | 251,547 | 251,436 | +111 (+0.0%) |
| FrameOS apps (Nim) | 190,404 | 190,356 | +48 (+0.0%) |
| ESP-IDF misc | 181,395 | 181,564 | -169 (-0.1%) |
| Embedded font | 146,362 | 146,362 | ±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,519 | 132,439 | +80 (+0.1%) |
| lwIP / HTTP / WebSocket | 126,779 | 126,800 | -21 (-0.0%) |
| libc / libm / newlib | 116,263 | 116,263 | ±0 |
| Storage (SPIFFS / FatFS / SD / NVS) | 94,108 | 94,080 | +28 (+0.0%) |
| Nim packages (chrono, zippy, chroma, qrgen, ...) | 71,933 | 71,849 | +84 (+0.1%) |
| Display drivers (C) | 64,962 | 64,946 | +16 (+0.0%) |
| Crypto (monocypher) | 35,141 | 35,141 | ±0 |
| Total mapped flash | 3,132,541 | 3,116,676 | +15,865 (+0.5%) |
Inside each subsystem
FrameOS core (Nim) — 487,875
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
frameos/js_runtime |
118,440 | 115,444 | +2,996 (+2.6%) |
frameos/utils |
117,350 | 112,401 | +4,949 (+4.4%) |
frameos/interpreter.nim |
99,980 | 100,264 | -284 (-0.3%) |
embedded_main.nim |
19,252 | 19,252 | ±0 |
embedded_runtime.nim |
17,830 | 17,834 | -4 (-0.0%) |
lib/tz.nim |
16,722 | 16,722 | ±0 |
frameos_nim_glue.c.obj |
11,455 | 10,635 | +820 (+7.7%) |
frameos/planner.nim |
9,689 | 9,681 | +8 (+0.1%) |
frameos/event_loop.nim |
8,412 | 8,412 | ±0 |
frameos/types.nim |
7,909 | 7,909 | ±0 |
frameos/values.nim |
7,699 | 7,699 | ±0 |
frameos/single_scene_host.nim |
6,687 | 6,712 | -25 (-0.4%) |
frameos/apps.nim |
6,585 | 6,585 | ±0 |
frameos/spool.nim |
5,787 | 5,787 | ±0 |
frameos/input_state.nim |
5,079 | 3,766 | +1,313 (+34.9%) |
embedded_scene.nim |
4,945 | 4,945 | ±0 |
frameos/events_gen.nim |
3,926 | 3,948 | -22 (-0.6%) |
fos_netguard.c.obj |
3,532 | 2,179 | +1,353 (+62.1%) |
frameos/app_config.nim |
2,939 | 2,935 | +4 (+0.1%) |
frameos/reboot_reason.nim |
2,648 | 2,648 | ±0 |
frameos/node_config.nim |
2,618 | 2,618 | ±0 |
frameos/app_capabilities.nim |
2,489 | 2,489 | ±0 |
frameos/events.nim |
2,410 | 2,410 | ±0 |
frameos/refresh_interval.nim |
1,635 | 1,639 | -4 (-0.2%) |
frameos/runtime_diagnostics.nim |
767 | 767 | ±0 |
frameos/event_log.nim |
415 | 431 | -16 (-3.7%) |
fos_version.c.obj |
328 | 328 | ±0 |
frameos/cloud |
— | 255 | -255 (-100.0%) |
frameos/channels.nim |
152 | 152 | ±0 |
frameos/ids.nim |
137 | 137 | ±0 |
frameos/hal |
44 | 44 | ±0 |
frameos/retired_apps.nim |
14 | 14 | ±0 |
QuickJS — 360,345
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
quickjs.c.obj |
287,826 | 287,846 | -20 (-0.0%) |
libunicode.c.obj |
50,178 | 50,178 | ±0 |
libregexp.c.obj |
13,995 | 13,999 | -4 (-0.0%) |
dtoa.c.obj |
5,681 | 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 — 304,382
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
pixie/fontformats/opentype.nim |
55,460 | 55,460 | ±0 |
pixie/fileformats/webp.nim |
37,493 | 37,493 | ±0 |
pixie/fileformats/svg.nim |
36,975 | 36,983 | -8 (-0.0%) |
pixie/paths.nim |
32,895 | 32,875 | +20 (+0.1%) |
pixie/fileformats/jpeg.nim |
29,424 | 29,436 | -12 (-0.0%) |
pixie/fileformats/png.nim |
22,097 | 22,101 | -4 (-0.0%) |
pixie/images.nim |
15,771 | 15,779 | -8 (-0.1%) |
pixie/fonts.nim |
10,995 | 10,995 | ±0 |
pixie/paints.nim |
9,869 | 9,869 | ±0 |
pixie/fileformats/bmp.nim |
8,286 | 8,258 | +28 (+0.3%) |
pixie/common.nim |
7,389 | 7,413 | -24 (-0.3%) |
pixie/blends.nim |
6,528 | 6,516 | +12 (+0.2%) |
pixie/fileformats/gif.nim |
5,957 | 5,965 | -8 (-0.1%) |
pixie/inflatestream.nim |
5,233 | 5,233 | ±0 |
pixie.nim |
5,220 | 5,224 | -4 (-0.1%) |
pixie/fileformats/webp_vp8_tables.nim |
3,881 | 3,881 | ±0 |
pixie/fileformats/ppm.nim |
3,729 | 3,713 | +16 (+0.4%) |
pixie/contexts.nim |
3,050 | 3,054 | -4 (-0.1%) |
pixie/fileformats/qoi.nim |
2,726 | 2,702 | +24 (+0.9%) |
pixie/internal.nim |
754 | 754 | ±0 |
pixie/rgb565.nim |
385 | 385 | ±0 |
pixie/fontformats/svgfont.nim |
215 | 215 | ±0 |
pixie/decodebudget.nim |
50 | 50 | ±0 |
Wi-Fi stack — 295,296
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
libnet80211.a |
136,164 | 136,168 | -4 (-0.0%) |
libpp.a |
62,154 | 62,154 | ±0 |
libwpa_supplicant.a |
54,900 | 54,904 | -4 (-0.0%) |
libphy.a |
34,176 | 34,176 | ±0 |
libesp_wifi.a |
4,780 | 4,780 | ±0 |
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 — 251,547
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
pure/collections/tables.nim |
72,312 | 72,312 | ±0 |
system.nim |
48,509 | 48,457 | +52 (+0.1%) |
pure/unicode.nim |
17,405 | 17,405 | ±0 |
pure/times.nim |
16,884 | 16,888 | -4 (-0.0%) |
pure/json.nim |
13,722 | 13,722 | ±0 |
std/private/dragonbox.nim |
10,351 | 10,351 | ±0 |
pure/strutils.nim |
8,043 | 8,047 | -4 (-0.0%) |
pure/parsexml.nim |
6,003 | 6,011 | -8 (-0.1%) |
pure/algorithm.nim |
5,372 | 5,372 | ±0 |
pure/base64.nim |
5,290 | 5,290 | ±0 |
pure/hashes.nim |
4,181 | 4,181 | ±0 |
pure/xmlparser.nim |
3,555 | 3,555 | ±0 |
pure/parsejson.nim |
3,553 | 3,553 | ±0 |
std/formatfloat.nim |
3,500 | 3,504 | -4 (-0.1%) |
pure/uri.nim |
3,225 | 3,225 | ±0 |
pure/streams.nim |
2,820 | 2,820 | ±0 |
pure/strformat.nim |
2,546 | 2,546 | ±0 |
std/syncio.nim |
2,339 | 2,355 | -16 (-0.7%) |
pure/collections/sets.nim |
2,075 | 2,075 | ±0 |
pure/xmltree.nim |
2,047 | 2,047 | ±0 |
pure/lexbase.nim |
1,801 | 1,801 | ±0 |
pure/parseutils.nim |
1,750 | 1,750 | ±0 |
system/exceptions.nim |
1,598 | 1,598 | ±0 |
pure/strtabs.nim |
1,572 | 1,572 | ±0 |
pure/pathnorm.nim |
1,336 | 1,336 | ±0 |
pure/options.nim |
1,016 | 1,016 | ±0 |
std/private/ospaths2.nim |
994 | 994 | ±0 |
pure/collections/lists.nim |
979 | 979 | ±0 |
pure/math.nim |
841 | 841 | ±0 |
pure/collections/deques.nim |
822 | 822 | ±0 |
pure/random.nim |
696 | 696 | ±0 |
std/private/digitsutils.nim |
651 | 651 | ±0 |
std/oserrors.nim |
633 | 633 | ±0 |
std/private/osdirs.nim |
572 | 572 | ±0 |
system/dollars.nim |
529 | 529 | ±0 |
std/monotimes.nim |
501 | 406 | +95 (+23.4%) |
std/private/oscommon.nim |
329 | 329 | ±0 |
std/envvars.nim |
250 | 250 | ±0 |
std/private/decode_helpers.nim |
240 | 240 | ±0 |
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 |
std/assertions.nim |
87 | 87 | ±0 |
core/macros.nim |
65 | 65 | ±0 |
system/ctypes.nim |
9 | 9 | ±0 |
FrameOS apps (Nim) — 190,404
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
apps/data/icalJson |
50,745 | 50,733 | +12 (+0.0%) |
apps/render/calendar |
30,942 | 30,874 | +68 (+0.2%) |
apps/data/localImage |
10,432 | 10,432 | ±0 |
apps/render/split |
9,736 | 9,772 | -36 (-0.4%) |
apps/data/eventsToAgenda |
9,068 | 9,068 | ±0 |
apps/render/zoomPan |
8,600 | 8,648 | -48 (-0.6%) |
apps/apps.nim |
7,255 | 7,247 | +8 (+0.1%) |
apps/render/text |
5,447 | 5,455 | -8 (-0.1%) |
apps/data/xmlToJson |
5,428 | 5,428 | ±0 |
apps/render/svg |
5,264 | 5,192 | +72 (+1.4%) |
apps/render/image |
4,696 | 4,708 | -12 (-0.3%) |
apps/logic/setAsState |
3,477 | 3,453 | +24 (+0.7%) |
apps/data/rotateImage |
3,461 | 3,465 | -4 (-0.1%) |
apps/data/downloadImage |
3,313 | 3,325 | -12 (-0.4%) |
apps/render/gradient |
3,205 | 3,229 | -24 (-0.7%) |
apps/data/qr |
3,118 | 3,122 | -4 (-0.1%) |
apps/data/downloadUrl |
3,053 | 3,053 | ±0 |
apps/render/color |
2,836 | 2,824 | +12 (+0.4%) |
apps/data/newImage |
2,668 | 2,668 | ±0 |
apps/data/resizeImage |
2,558 | 2,558 | ±0 |
apps/render/opacity |
2,312 | 2,296 | +16 (+0.7%) |
apps/data/log |
2,299 | 2,299 | ±0 |
apps/data/prettyJson |
2,225 | 2,225 | ±0 |
apps/data/clock |
1,871 | 1,875 | -4 (-0.2%) |
apps/data/parseJson |
1,848 | 1,856 | -8 (-0.4%) |
apps/logic/nextSleepDuration |
1,663 | 1,663 | ±0 |
apps/logic/ifElse |
1,494 | 1,494 | ±0 |
apps/logic/breakIfRendering |
1,390 | 1,394 | -4 (-0.3%) |
ESP-IDF misc — 181,395
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
libesp_hw_support.a |
37,632 | 37,632 | ±0 |
libhal.a |
21,869 | 21,865 | +4 (+0.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,756 | 7,756 | ±0 |
libconsole.a |
5,733 | 5,733 | ±0 |
libjson.a |
4,940 | 4,940 | ±0 |
libesp_driver_gpio.a |
3,890 | 3,878 | +12 (+0.3%) |
libbootloader_support.a |
3,817 | 3,813 | +4 (+0.1%) |
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,253 | 3,253 | ±0 |
libesp_driver_ledc.a |
3,054 | 3,054 | ±0 |
libesp_mm.a |
2,451 | 2,451 | ±0 |
libapp_update.a |
2,426 | 2,414 | +12 (+0.5%) |
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,362
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
assets/fonts.nim |
146,362 | 146,362 | ±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,519
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
libmbedcrypto.a |
71,379 | 71,291 | +88 (+0.1%) |
libmbedtls.a |
45,799 | 45,799 | ±0 |
libmbedx509.a |
7,084 | 7,092 | -8 (-0.1%) |
libesp-tls.a |
6,705 | 6,705 | ±0 |
libesp_https_server.a |
1,552 | 1,552 | ±0 |
lwIP / HTTP / WebSocket — 126,779
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
liblwip.a |
78,385 | 78,445 | -60 (-0.1%) |
libhttp_parser.a |
10,350 | 10,350 | ±0 |
libesp_http_server.a |
10,020 | 10,020 | ±0 |
libtcp_transport.a |
8,241 | 8,245 | -4 (-0.0%) |
libespressif__esp_websocket_client.a |
6,818 | 6,822 | -4 (-0.1%) |
libesp_http_client.a |
6,666 | 6,666 | ±0 |
libesp_netif.a |
6,299 | 6,252 | +47 (+0.8%) |
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,108
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
libspiffs.a |
20,380 | 20,380 | ±0 |
libfatfs.a |
20,133 | 20,133 | ±0 |
libspi_flash.a |
14,168 | 14,168 | ±0 |
libnvs_flash.a |
13,705 | 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,964 | 1,956 | +8 (+0.4%) |
libesp_vfs_console.a |
678 | 678 | ±0 |
libnvs_sec_provider.a |
5 | 5 | ±0 |
Nim packages (chrono, zippy, chroma, qrgen, ...) — 71,933
| Part | This PR | v2026.10.15 | Δ |
|---|---|---|---|
QRgen 3.1.0 |
22,056 | 22,060 | -4 (-0.0%) |
chrono 0.3.1 |
15,658 | 15,586 | +72 (+0.5%) |
zippy 0.10.19 |
15,216 | 15,200 | +16 (+0.1%) |
chroma 1.0.0 |
14,714 | 14,714 | ±0 |
checksums 0.2.1 |
3,371 | 3,371 | ±0 |
flatty 0.3.4 |
533 | 533 | ±0 |
jsony 1.1.5 |
272 | 272 | ±0 |
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 |
+5,079 | 5,079 | — |
pkgs/QRgen-3.1.0/QRgen/renderer.nim |
-3,780 | — | 3,780 |
frameos/js_runtime/app_runtime.nim |
+2,216 | 74,851 | 72,635 |
frameos/utils/http_client.nim |
+1,815 | 11,805 | 9,990 |
frameos_nim_glue.c.obj |
+820 | 11,455 | 10,635 |
fos_client.c.obj |
+691 | 12,957 | 12,266 |
frameos/js_runtime/burrito.nim |
+603 | 8,097 | 7,494 |
esp_efuse_utility.c.obj |
+595 | 135,683 | 135,088 |
fos_cloud.c.obj |
+393 | 19,651 | 19,258 |
frameos/interpreter.nim |
-284 | 99,980 | 100,264 |
fos_ota.c.obj |
+172 | 5,639 | 5,467 |
fos_settings.c.obj |
+104 | 7,722 | 7,618 |
pkgs/chrono-0.3.1/chrono.nim |
+72 | 15,658 | 15,586 |
apps/render/calendar/app_loader.nim |
+68 | 7,125 | 7,057 |
fos_scenes.c.obj |
-63 | 7,515 | 7,578 |
Largest 30 objects
| Object | Subsystem | This PR | v2026.10.15 | Δ |
|---|---|---|---|---|
quickjs.c.obj |
QuickJS | 287,826 | 287,846 | -20 (-0.0%) |
assets/fonts.nim |
Embedded font | 146,362 | 146,362 | ±0 |
esp_efuse_utility.c.obj |
String pool (attributed to efuse) | 135,683 | 135,088 | +595 (+0.4%) |
frameos/interpreter.nim |
FrameOS core (Nim) | 99,980 | 100,264 | -284 (-0.3%) |
frameos/js_runtime/app_runtime.nim |
FrameOS core (Nim) | 74,851 | 72,635 | +2,216 (+3.1%) |
nim/lib/pure/collections/tables.nim |
Nim stdlib | 72,312 | 72,312 | ±0 |
pkgs/pixie-6.1.0/pixie/fontformats/opentype.nim |
pixie | 55,460 | 55,460 | ±0 |
libunicode.c.obj |
QuickJS | 50,178 | 50,178 | ±0 |
nim/lib/system.nim |
Nim stdlib | 48,509 | 48,457 | +52 (+0.1%) |
apps/data/icalJson/ical.nim |
FrameOS apps (Nim) | 45,028 | 45,016 | +12 (+0.0%) |
pkgs/pixie-6.1.0/pixie/fileformats/webp.nim |
pixie | 37,493 | 37,493 | ±0 |
pkgs/pixie-6.1.0/pixie/fileformats/svg.nim |
pixie | 36,975 | 36,983 | -8 (-0.0%) |
frameos/utils/image.nim |
FrameOS core (Nim) | 35,946 | 35,942 | +4 (+0.0%) |
pkgs/pixie-6.1.0/pixie/paths.nim |
pixie | 32,895 | 32,875 | +20 (+0.1%) |
monocypher.c.obj |
Crypto (monocypher) | 31,916 | 31,916 | ±0 |
frameos/js_runtime/runtime.nim |
FrameOS core (Nim) | 31,662 | 31,686 | -24 (-0.1%) |
pkgs/pixie-6.1.0/pixie/fileformats/jpeg.nim |
pixie | 29,424 | 29,436 | -12 (-0.0%) |
apps/render/calendar/app.nim |
FrameOS apps (Nim) | 23,817 | 23,817 | ±0 |
fos_http.c.obj |
fos_* firmware shell (C) | 22,185 | 22,185 | ±0 |
pkgs/pixie-6.1.0/pixie/fileformats/png.nim |
pixie | 22,097 | 22,101 | -4 (-0.0%) |
fos_cloud.c.obj |
fos_* firmware shell (C) | 19,651 | 19,258 | +393 (+2.0%) |
embedded_main.nim |
FrameOS core (Nim) | 19,252 | 19,252 | ±0 |
frameos/utils/status_screen.nim |
FrameOS core (Nim) | 17,947 | 17,943 | +4 (+0.0%) |
x509_crt_bundle.S.obj |
mbedTLS + certificates | 17,928 | 17,928 | ±0 |
embedded_runtime.nim |
FrameOS core (Nim) | 17,830 | 17,834 | -4 (-0.0%) |
nim/lib/pure/unicode.nim |
Nim stdlib | 17,405 | 17,405 | ±0 |
frameos/utils/asset_colors.nim |
FrameOS core (Nim) | 17,333 | 17,333 | ±0 |
nim/lib/pure/times.nim |
Nim stdlib | 16,884 | 16,888 | -4 (-0.0%) |
lib/tz.nim |
FrameOS core (Nim) | 16,722 | 16,722 | ±0 |
pkgs/pixie-6.1.0/pixie/images.nim |
pixie | 15,771 | 15,779 | -8 (-0.1%) |
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.
Shard 1 of the Nim tests fails to link on main and on every PR since this morning, with no code at fault:
(main 39118817269 and #567 identical; main 39118507287 the same kind in
test_refresh_interval.)Cause. Nim reuses a module's object file when the C it generates equals the
.con disk and the.ois newer (shouldRecompile, compiler/cgen.nim). Nothing checks that the.ocame from that.c. The warm cache was one shared directory per shard on/mnt/cache. Overlapping runs copied into it (rsync -a) and out of it (cp -a) at the same time, so a restore could pair one build's.cwith another build's newer.o. Nim linked the stale object, and theif: always()save after the run wrote the pair back for every later run. The workflow comment assumed "Nim validates each object by hash anyway"; it doesn't.Fix.
frameos/tools/ci_nimcache.sh restore|save <shard>:rsync --link-deston the snapshot this job restored, so unchanged files are hardlinks and a save costs only what the run rebuilt. Then it swapsshard-N.currentin one rename. Snapshots are never modified after that..onewer than its.c.nimcache/frameos-tests-snapshots): one cold build per shard, and the poisoned pairs are left behind.Tested in a Linux container: three savers doing restore → rebuild 8 of 40 test dirs → save cycles against four restorers for 30 s. 227 restores, 0 with a test dir mixing two builds. Hardlinking and the round trip are checked too. The previous scheme under the same load: 250 of 266 restores mixed, and the shared dir itself ended up holding a mixed pair. Shellcheck clean.
Host disk: 56 G free on monster; the first snapshots take ~17 G. The old
nimcache/frameos-tests/shard-{1..8}dirs (~31 G, shards 5–8 unused since the move to four shards) can be deleted once branches carry this (noted intools/gha-runners/README.md). I haven't touched them.🤖 Generated with Claude Code