docs: the millisecond clock stays 64 bits, owner-refused
608 B of flash, 7.6 % of the image, and it is not available: this board runs continuously and an uptime that restarts every 49.7 days is not acceptable, which is what a 32-bit millisecond counter wraps at. The tick split goes with it. It only ever made sense beside the narrowing, and on its own it costs 66 B to buy about 0.4 % of a CPU nothing here is competing for. Both are recorded rather than deleted, and that is the point of the change: the numbers are real and re-measurable, so someone will find 608 B again and read it as an opportunity. What they need with it is the reason it was refused. Docs only; five tests green. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
57
dev/tasks.md
57
dev/tasks.md
@@ -5,35 +5,36 @@ rule 20).
|
|||||||
|
|
||||||
## Open
|
## Open
|
||||||
|
|
||||||
- [ ] decide whether the millisecond clock stays 64 bits. **Measured: 608 B of
|
Nothing.
|
||||||
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
|
## Decided against
|
||||||
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
|
Both of these are measured, and both are recorded here rather than deleted so
|
||||||
the answer decides 608 B. If it is, the three call sites in
|
that the next person to measure them does not read a number as an opportunity
|
||||||
`statistics.hpp` and `terminal.hpp` move to subtraction in the same
|
and re-propose work the owner has already refused.
|
||||||
change, and that is the whole of the work.
|
|
||||||
|
|
||||||
- [ ] the 1 kHz tick's own cost, which is separate and smaller. The compare
|
### The millisecond clock stays 64 bits
|
||||||
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
|
Narrowing `uptime::millis()` and the three timestamps that hold its value from
|
||||||
0.4 % of the CPU** - `millis()` then reassembles the halves, and the
|
`uint64_t` to `uint32_t` is **608 B of flash, 7.6 % of the image** (8004 B down
|
||||||
readers pay for it. It is the right change only if the tick's cycles ever
|
to 7396), plus 16 B of RAM.
|
||||||
matter; today nothing here is timing-critical. Falls away entirely if the
|
|
||||||
counter narrows above, which is the reason to decide that one first.
|
**Refused, owner-stated: this board runs continuously and an uptime that
|
||||||
|
restarts every 49.7 days is not acceptable.** That is what a 32-bit
|
||||||
|
millisecond counter wraps at, and the display is not the only cost - the
|
||||||
|
interval tests would have to become subtractions, since `now - last >=
|
||||||
|
interval` survives a wrap where `now >= last + interval` does not, and
|
||||||
|
`terminal.hpp`'s monitor tick is written the second way. The 64-bit counter is
|
||||||
|
what puts the wrap out of reach, which is the property being bought.
|
||||||
|
|
||||||
|
### The 1 kHz tick keeps its 64-bit increment
|
||||||
|
|
||||||
|
The compare handler increments 64 bits, so it calls libgcc's `__adddi3_s8`, and
|
||||||
|
a call inside a signal handler decides the prologue - twelve push/pop pairs for
|
||||||
|
what the helper might clobber. Splitting the counter into two 32-bit halves
|
||||||
|
removes the call and keeps the full range, taking the handler from ~47
|
||||||
|
instructions to ~26 with the carry running once every 49.7 days.
|
||||||
|
|
||||||
|
**Refused: it costs 66 B of flash to buy about 0.4 % of the CPU**, and nothing
|
||||||
|
here is timing-critical. It was only ever worth considering alongside the
|
||||||
|
narrowing above, which is refused outright.
|
||||||
|
|||||||
Reference in New Issue
Block a user