Two findings from the flash sweep, both measured and neither taken, because each is a decision rather than a defect. Narrowing uptime::millis() and its three timestamps to 32 bits is 608 B, 7.6 % of the image, and 16 B of RAM. The reason it is not a free win is not the display: a 32-bit millisecond counter wraps every 49.7 days on a board that runs continuously, and the interval tests would have to become subtractions, since `now - last >= interval` survives a wrap where `now >= last + interval` does not - which is how terminal.hpp's monitor tick is written today. The 64-bit counter is what puts the wrap out of reach, so this is a question about a wrapping uptime display, and the answer decides 608 B. The 1 kHz tick's own prologue is the smaller one. The handler increments 64 bits, so it calls __adddi3_s8, and a call in a signal handler decides the prologue - twelve push/pop pairs for what the helper might clobber. Two 32-bit halves remove the call and keep the range, taking the handler from ~47 instructions to ~26 with the carry running once every 49.7 days. Not taken either: it costs 66 B of flash to buy about 0.4 % of the CPU, and nothing here is timing-critical. This repo had nowhere to record work, so it has a tracker now. Docs only; the image is unchanged at 8004 B and the suite is green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
40 lines
2.1 KiB
Markdown
40 lines
2.1 KiB
Markdown
# Tasks
|
|
|
|
This file is current work. The repo is the sole task tracker (libavr guidance
|
|
rule 20).
|
|
|
|
## Open
|
|
|
|
- [ ] decide whether the millisecond clock stays 64 bits. **Measured: 608 B of
|
|
flash, 7.6 % of the image**, plus 16 B of RAM - `uptime::millis()` and the
|
|
three timestamps that hold its value narrowed from `uint64_t` to
|
|
`uint32_t`, 8004 B down to 7396.
|
|
|
|
It is not free, and the price is not only the display. A 32-bit
|
|
millisecond counter wraps every **49.7 days**, and this board runs
|
|
continuously, so two things follow. The `uptime` command would restart
|
|
from zero at each wrap. And the interval tests would have to be rewritten
|
|
as subtractions - `now - last >= interval` is correct across a wrap where
|
|
`now >= last + interval` is not, and `terminal.hpp`'s monitor tick is
|
|
written the second way today. That shape is *why* the counter is 64 bits:
|
|
it puts the wrap out of reach so a naive comparison cannot be wrong.
|
|
|
|
So the question is whether a wrapping uptime display is acceptable, and
|
|
the answer decides 608 B. If it is, the three call sites in
|
|
`statistics.hpp` and `terminal.hpp` move to subtraction in the same
|
|
change, and that is the whole of the work.
|
|
|
|
- [ ] the 1 kHz tick's own cost, which is separate and smaller. The compare
|
|
handler increments a 64-bit counter, so it calls libgcc's `__adddi3_s8`,
|
|
and a call inside a signal handler decides the prologue - twelve push/pop
|
|
pairs to cover what the helper might clobber. Splitting the counter into
|
|
two 32-bit halves removes the call and halves the prologue: the handler
|
|
goes from ~47 instructions to ~26 and keeps the full 64-bit range, the
|
|
carry running once every 49.7 days.
|
|
|
|
**Measured and not taken, because it costs 66 B of flash to save about
|
|
0.4 % of the CPU** - `millis()` then reassembles the halves, and the
|
|
readers pay for it. It is the right change only if the tick's cycles ever
|
|
matter; today nothing here is timing-critical. Falls away entirely if the
|
|
counter narrows above, which is the reason to decide that one first.
|