Load averages: uptime and w do not report the machine's load¶
On Amix, the number uptime and w print is unrelated to the kernel's own load average ✅. Its
flavour — a permanently flat 0.00, 0.00, 0.00, or values in the hundreds of thousands — depends
only on what happens to sit at the address they mistakenly read. A flat 0.00 is not an idle
machine; it is the same defect wearing a more convincing disguise. Anyone who has ever concluded
"this Amix box is idle" from uptime has concluded nothing at all.
Both halves below reproduce on the shipped stock 2.1 kernel — these are properties of Amix as
Commodore released it, measured on a stock 68030 machine in a controlled 40-minute, 78-sample run
with the run queue independently tracked by ps -el throughout ✅.
Defect 1 — the reader: nlist(3) succeeds and hands back a non-address ✅¶
avenrun, the kernel's three load accumulators, is a C tentative definition — an ELF SHN_COMMON
symbol — and /stand/unix is an ET_REL relocatable object, so the symbol has no address in the
file: nlist(3) returns success with the symbol's alignment (4) as its value, and the
reader prints whatever pointer-shaped memory lives at address 4 on that boot. The same box produced
both wrongness flavours at once: uptime printed 0.00 in all 78 samples while a direct read
of address 4 rendered as 458759.84 / 63495.78 / 63498.61. This is the
COMMON-symbol trap
in its natural habitat; the reader half is Amix's own addition (stock SVR4's w prints no load
average at all) ✅.
Defect 2 — the kernel: the load count omits the on-CPU process, so it reads exactly N−1 ✅¶
Fix the reader and the number is still wrong. The accounting that produces the runnable count
classifies every process by scheduling state and omits the state meaning "currently executing on
a processor" — on a uniprocessor, exactly one process whenever the machine is busy. Measured as a
prediction test: 1 spinner → 0.00, 2 → 1.00, 3 → 1.99, with ps confirming the run
queue moved 2→5 in step. This half is inherited from the SVR4 lineage, not introduced by the
port ✅ (stated as behaviour; the ancestral source is proprietary and is not quoted).
Everything either side of the two defects is healthy ✅: given a correct count, the averaging is
textbook — right time constants, right decay ordering (1-min crosses below 5-min below 15-min),
FSCALE = 256. Only the input count and the reader are wrong.
Reading the real value today, with no fix ✅¶
adb -k reproduces the boot loader's COMMON placement — with two load-bearing conditions: the
namelist must be the kernel actually running, and when the running kernel exists in no file
(loaded from a raw slice), adb -k /stand/unix fails silently with plausible zeros — replay the
loader's allocation host-side instead. Both conditions, the ten-second COMMON tells, and the
fallbacks are on the
reverse-engineering page.
crash(1M) does not work here (process slot out of bounds) ✅.
The blast radius is every nlist-based consumer of a COMMON kernel symbol — uptime and w
confirmed; anything else reading avenrun the same way is equally affected and equally silent 🟡.
The fix, if anyone wants it, is cheap on both halves: resolve through the running image in the
reader, add the missing state to the kernel's accounting switch. Neither has been attempted ✅.
The same silent-miss on real hardware: the kernel load base moves with the accelerator card ✅¶
The defect above is a plausible-but-wrong number read from an address that isn't what you think it
is. The same class recurs one level down, at the kernel's load base — the address the kernel
image itself is loaded at (a load address, not to be confused with the load average the rest of
this page is about). Any host-side tool that computes a runtime kernel address as load_base +
offset — to read a counter, a symbol, or a magic word out of /dev/mem — inherits exactly the
COMMON-symbol trap's failure signature if it pins the wrong base: an adb//dev/mem read at the
wrong address returns a plausible number rather than an error ✅.
On an Amiga running Amix from a raw-slice-loaded kernel, the load base is set by the accelerator
card's fast-RAM, not by the machine — so it moves when the CPU card changes ✅. A kernel loaded
into an accelerator's 32 MB fast-RAM region loads at that region's base: a 68060 Mercury card
places it at 0x08000000; swapping to an A3640/68040 moves it to 0x07000000 — a 16 MiB
shift. Every runtime address computed off the old base is then wrong by that amount, silently. The
load base is therefore not a constant to hardcode; it is an input to verify ✅.
The remedy that works: a fail-closed magic-word gate ✅. The port kernel's counter blocks carry
magic words (fpe_magic = "FPE!" 0x46504521, f60_magic = "FP60", and siblings fpc_magic /
fpi_magic / fpe_abort_magic). Before trusting any derived address, read the anchor magic at its
computed address and compare it against the value the ELF artifact actually holds (read from the
artifact, never a hardcoded table). A mismatch means the base is wrong — refuse loudly and try
the other candidate; probing {0x08000000, 0x07000000} and keeping the base whose magic reads back
correct turns a silent megabyte-off read into a caught, named error. This is implemented and verified
in amix-kerntools/tools/comaddr.py (commit 4cc29cc): --load-base with the fail-closed gate (a
deliberate wrong base is refused, exit 3, naming the base to try; --discover picks the correct
candidate), a host-static 18-case selftest — the box read is an input, so the check is
offline-testable ✅. The magic words themselves are the software-FPE lane's
counter anchors; reported firsthand from real hardware, where a 68060→68040 card swap moved the base
and the magic-word check caught it on the first read ✅.
The through-line with Defect 1 and the COMMON-symbol trap: a wrong-but-plausible number from an address that moved is only ever caught by validating the read against something the target must independently satisfy — a magic word here, the running kernel's own namelist there.
See also¶
- Kernel reverse-engineering — the COMMON-symbol law and the load-bias trap, kept distinct.
- Quirks §38 — the checklist row.
- Amix on 68040/68060 — the software-FPE lane whose counter magic words anchor the load-base gate.
Sources¶
- First-party load-average measurement — a stock Amix 2.1 68030 machine, a controlled 40-minute,
78-sample run with the run queue independently tracked by
ps -elthroughout ✅:nlist(3)resolvingavenrun(aSHN_COMMONsymbol in theET_REL/stand/unix) to its alignment (4) and succeeding; the flat0.00vs. six-digit-garbage duality read at address 4; the N−1 on-CPU-omission prediction test (1 spinner → 0.00, 2 → 1.00, 3 → 1.99); and the healthy averaging either side (FSCALE = 256, correct decay ordering). The reader half is Amix's own addition (stock SVR4wprints no load average); the count half is inherited from the SVR4 lineage (behaviour only, source not quoted). - First-party 68040/68060 port campaign +
amix-kerntools— the kernel-load-base finding ✅: a raw-slice-loaded kernel loads at the accelerator's fast-RAM base (68060 Mercury0x08000000, A3640/680400x07000000), so it moves on a card swap and a pinned base silently reads the wrong memory (the same silent-miss class as a stale COMMON address); the fail-closed magic-word gate (fpe_magic/f60_magic/…, read from the ELF artifact) as the remedy, implemented and verified inamix-kerntools/tools/comaddr.py@4cc29cc(host-static 18-case selftest;--load-base/--discover), corroborated firsthand on real hardware by a 68060→68040 card swap the check caught on the first read.