Repository navigation
savings floor: tft_graph 20,365 -> 20,135 B after #307's alarm-limits box, decoded, nothing leaked (issue #314) - #316
Merged
Conversation
… box, decoded symbol by symbol, nothing leaked (issue #314) The nightly savings job (.github/workflows/savings.yml) has failed on main since 2026-11-01, always at 7b85181, on one line: tft_graph saves 20,135 B against a floor of 20,365 B (230 B under, 222 B past FLASH_TOL). The job opened issue #314 itself. No PR runs this gate, so the merges of 2026-10-31 did not see it. Nothing of the graph leaked; this records the floor after the drop was decoded and after the maintainer chose between the two ways out. Measured per merge (pico_w_release and _sav_tft_graph_off, each tree's own tools/measure_savings.py, the linker fill read from the map). At 7b85181 every number of the 16 features equals the CI's run of 2026-11-03, and the base .bin is main's byte for byte (sha256 a39bf356...): tree used on / off fill on / off saved ae87f6d (the last green) 1,024,060 / 1,003,692 685 / 682 20,365 aaccce3 (#307, F3) 1,024,164 / 1,004,020 687 / 682 20,139 96f503a (#308, alignment) 1,024,380 / 1,004,244 683 / 682 20,135 7b85181 (#311 and #312 change neither image) as 96f503a 20,135 #307 costs the image with the graph 104 B and the image without it 328 B; #308 takes 4 B more, within the tolerance. Per section and symbol (the map and nm -S, ae87f6d -> aaccce3), all of it is in .text. The code the switch removes whole grows 12 B in six functions (drawGraphDetailScreen 3,068 -> 3,076 B): the graph still goes entirely. The always-on code the switch changes accounts for -238 B net in 65 functions, 62 of DisplayManager and three of 4 B outside it (AppManager::setup and two WebManager touch routes): 45 shrink by 328 B and 20 grow by 90 B. The largest are loopCore1 -56, handleTouch -28, pinSubmit -16, drawAlarmEdit -16, showSettingsPassword -12 and drawMelodySelect -12; 29 move -4 B and 16 move +4 B. Why. #307 put AlarmLimitsSnap _limitsSaved (68 B) in the middle of DisplayManager (the TFT block of src/DisplayManager.h), before _sharedState, so every member after it moves 68 B. The graph package (5,872 B) also comes after the box, and it is what tells the two images apart: with the switch off, the members after it sit near the start of the object, where the Cortex-M0+ builds an offset with movs + lsls or with a literal word depending on its value, and moving 68 B changes that choice in dozens of functions. loopCore1's most used member shows how. In the graph-off image it was at 0x4dc (1,244), which no shifted 8-bit movs reaches: 28 literal loads and 4 pool words. #307 moved it to 0x520 (1,312 = 164 << 3), which the compiler builds with movs #164 and lsls #3 and no literal: the 28 loads became 27 pairs of 4 B each. Over the whole function, 23 fewer literal loads and 24 more pairs (5,260 -> 5,300 B). In the image with the graph the same member went from 0x1bcc to 0x1c14, both literal words: there loopCore1 has 4 fewer literal loads and shrank 16 B (5,696 -> 5,680). The graph package between the two images is 5,872 B before #307 (0x1bcc - 0x4dc) and 5,876 B after (0x1c14 - 0x520). It is the effect tools/arduino_pico_overrides/README.md measured on the web server (2026-10-14). The experiment (scratch copies of 7b85181, never committed): the box moved to the end of the class, or to just before the UI driver's members, brings the saving back to 20,369 B and shrinks the graph-off image by 224 B, but the published images grow (.bin, B): pico_w_release +8, pico2_w_release +144 (+136 before the driver's members), pico2_w_original +72, pico_w_test +16, pico_w_test_https +16, pico_wiretft_angulo +16, pico_w_asserts +8, pico_wiretft -32; pico_w_air, pico_w_alpha and pico_wire byte-equal (no TFT panel, no box). On pico2_w_release the box at the end changes 31 functions, +144 B net, exactly the .bin's growth (uiPass +32, handleTouch +26, uaMontarMenus +24, the constructor +16; redrawTopPanel -14); on pico_w_release it changes 53 input sections, +10 B of code and -2 B of linker fill, the image's 8 B. The main column of that table equals the "bin" of tools/flash_budget.json for every image that records one. The maintainer chose to lower the floor (2026-11-04): 224 B back for a variant no release publishes is not worth 8 B on pico_w_release and 144 B on pico2_w_release, the two published images with a panel. Floors, tools/measure_savings.py --check on e2fef36 before this commit: tft_graph 20,135 < 20,365 (rc 1, the only failing line); 11 features measure their floor exactly; tel_mqtt +2, web_history +4 and syslog +3 measure above it, as on 2026-10-30; cli_full measures 4 B under it, within the tolerance (it measured its floor exactly on 2026-10-30; the 4 B are new and were not decoded, and 5 B more would fail the night). Only the floor that must change changes: --only tft_graph --update rewrote one line of tools/feature_savings.json. RAM saved stays 2,232 B. docs/analysis/ECONOMIA_DE_RECURSOS.md (Living): the header line and a new section, "O piso do tft_graph depois da caixa dos limites de alarme (2026-11-04)", with the tables above and what is not proven: no member-by-member map of DisplayManager (the C++ is built without -g), and the instruction count made only in loopCore1 (handleTouch's mnemonics show the same swap, 31 fewer ldr and 24 more movs and lsls each; the other 63 functions were not decoded). CHANGELOG.md and CHANGELOG.pt-BR.md: one paragraph at the end of Unreleased's Flash section, as the previous floor drop has in v2.13.0's. Not done here: tools/feature_costs.json, the configurator's estimate, still holds the matrix of 2026-10-30, before #307, #308 and #311 changed the features' costs; AGENTS.md asks for measure_savings.py --matrix (70 builds) when a change moves a feature's size. That is its own change. Reviewed with a clean context (COM RESSALVAS): the floor change and the mechanism hold. Of its eight findings, six were about the text and are applied here, the main one a constructor counted twice by nm -S (its C1 and C2 symbols are one body); the CHANGELOG paragraph is the seventh; the eighth asked whether the night of 2026-11-04 also failed, and that run had not started when this was written (the last one is 2026-11-03, 13:27 UTC). Checks, host only, the shim's pio, under the build lock: tools/measure_savings.py --check before: rc 1, only tft_graph; after: rc 0, "16 recursos, nenhum abaixo do piso de economia." tools/test_measure_savings.py: 76/76 ok tools/check_angulo.py: 93 documents without emoji; git diff --check clean ci_gates_local.py --raso: 76 of 77 steps pass; the one failure is the fuzz step (this host's clang++ lacks libclang-cpp.so.18.1, as on every PR since 2026-10-23; CI runs it); one step is CI only (sanitizers) src/ untouched: no image changes. Not run on a board (nothing to run). Issue #314 stays open until the nightly job, dispatched on main after the merge, is green. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Uy7K2qPR85KvekjCnFFFxZ
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The nightly savings job (
.github/workflows/savings.yml, which no PR runs) has failed onmainsince 2026-11-01, always at7b851812, on one line:tft_graphsaves 20,135 B against a floor of 20,365 B. The job opened issue #314. This PR lowers that one floor to 20,135 B, after the drop was decoded symbol by symbol and the maintainer chose between the two ways out. No image changes.What moved the number
Measured on this host per merge (
pico_w_releaseand_sav_tft_graph_off, each tree's owntools/measure_savings.py, the linker fill read from the map). At7b851812all 16 features measure exactly what CI's run of 2026-11-03 printed, and the base.binismain's byte for byte.ae87f6d6, the last green nightaaccce35, #307 (F3, the alarm-limits box)96f503aa, #308 (the display alignment)7b851812(#311 and #312 change neither image)96f503aaNothing of the graph leaked: the code the switch removes whole grows 12 B, and the graph-named symbols left in the image without the graph are the same 4 (17 B) before and after. The drop is in always-on code the switch changes, -238 B net in 65 functions (45 shrink 328 B, 20 grow 90 B).
#307 put
AlarmLimitsSnap _limitsSaved(68 B) in the middle ofDisplayManager. Every member after it moves 68 B, and in the image without the graph those members sit near the start of the object, where the Cortex-M0+ builds an offset withmovs+lslsor a literal word depending on its value.loopCore1( )'s most used member went from0x4dc(no shifted 8-bitmovsreaches it: 28 literal loads) to0x520= 164 << 3 (27movs+lslspairs, 4 B each). In the image with the graph the same member went from0x1bccto0x1c14, both literal words, and the code barely moves.Why the floor moves instead of the box
On scratch copies of
7b851812(never committed), the box at the end of the class, or just before the UI driver's members, brings the saving back to 20,369 B and shrinks the graph-off image by 224 B. But the published images grow (.bin, B):pico_w_releasepico2_w_releasepico2_w_originalpico_w_test,pico_w_test_https,pico_wiretft_angulopico_w_assertspico_wiretftpico_w_air,pico_w_alpha,pico_wireThe maintainer chose to lower the floor (2026-11-04): 224 B back for a variant no release publishes is not worth 8 B on
pico_w_releaseand 144 B onpico2_w_release.The change
tools/feature_savings.json:tft_graph20,365 -> 20,135 B, written bymeasure_savings.py --only tft_graph --update(one line; RAM stays 2,232 B).docs/analysis/ECONOMIA_DE_RECURSOS.md(Living): the header line and a new section with the tables, the decoding and what is not proven.CHANGELOG.md,CHANGELOG.pt-BR.md: one paragraph at the end of Unreleased's Flash section, as v2.13.0's entry has for the previous drop.Checks (host only, the shim's pio, under the build lock)
tools/measure_savings.py --checkone2fef36cbefore: rc 1, onlytft_graph; after: rc 0, "16 recursos, nenhum abaixo do piso de economia." The other floors: 11 exact,tel_mqtt+2,web_history+4 andsyslog+3 above,cli_full4 B under (within the 8 B tolerance; new since 2026-10-30, not decoded).tools/test_measure_savings.py: 76/76.tools/check_angulo.py: clean.git diff --check: clean.ci_gates_local.py --raso: 76 of 77 steps pass; the one failure is the fuzz step, because this host'sclang++lackslibclang-cpp.so.18.1(CI runs it); one step is CI only (the sanitizers).nm -S).Not done here
tools/feature_costs.json, the configurator's estimate, still holds the matrix of 2026-10-30, before #307, #308 and #311 changed the features' costs. AGENTS.md asks formeasure_savings.py --matrix(70 builds) when a change moves a feature's size; that is its own change.After the merge
Dispatch
SIMUT savings watermarkonmainand close issue #314 by hand once it is green. This PR does not close it.🤖 Generated with Claude Code
https://claude.ai/code/session_01Uy7K2qPR85KvekjCnFFFxZ