aihydra — first boot
Written 2026-08-07, the evening the box was unboxed and the evening aibeast was declared dead. Ordered by irreversibility, not importance: things that can only be captured once come first, decisions come before the installs that depend on them.
Nothing here installs ROCm or a model. This gets the box up, proves it is healthy, captures the baselines that cannot be recovered later, and stops.
Phase 0 — before you press power (2 minutes)
Record the pre-boot standby draw from sensor.hardware_ai_hydra_power.
This is the number we never had for aibeast. inc-0005 was diagnosed entirely from
smart-plug statistics, and its should_have_caught_it reads: “A plug-power threshold
alarm — ‘AI Power fell below 5 W while a model was supposed to be resident’ — would have
fired within minutes.” You cannot set that threshold without knowing what normal looks
like, and you cannot measure clean standby again once the machine has a workload.
Write down: standby watts, powered off, nothing installed.
Phase 1 — first boot: BIOS before OS
Watch the plug, not the screen. We now know exactly what the three failure curves look
like (inc-0005, on_site): a healthy boot ramps and settles; a wedge sits flat around
45 W with no POST; a board-level fault shows standby with a slow hiccup hum and never
latches. If aihydra does anything other than ramp-and-settle, stop and compare against
that incident before troubleshooting from scratch.
Once it POSTs, go into BIOS/UEFI before installing anything and record rather than change:
- BIOS/UEFI version — and whether a newer one exists. Flashing firmware is far easier now than after an OS, a kernel and a working ROCm stack are on it.
- Memory configuration as reported
- The iGPU / UMA frame-buffer setting and its current value. Note it; do not tune it yet. GTT sizing is a kernel boot parameter on this platform, so the BIOS value is the floor rather than the whole story, and tuning either before a baseline exists means the change cannot be attributed.
⚠ Do not set amd_iommu=off yet. It is worth +5-12% on the iGPU and it disables the
NPU entirely — the two are mutually exclusive. That makes it a benchmark axis and an
architecture decision, not a setup step.
Phase 2 — the OS decision (yours, not mine)
The hard floor is kernel ≥6.18.4 with CWSR exported, firmware that is NOT
linux-firmware-20251125, and no amdgpu-dkms. Below that line ROCm reports wrong VGPR
counts and crashes, and every number measured on it is noise.
aibeast ran bare-metal Ubuntu. Consistency argues for the same; the kernel floor may argue otherwise, because distributions differ in how new a kernel they ship and how willing you are to run a mainline or HWE kernel to reach the floor. Check what your chosen installer actually provides against the floor before committing — this is the decision the rest of the stack sits on, and changing it later means a rebuild.
Related and worth deciding in the same sitting: static IP. Give aihydra its own —
do not reuse aibeast’s address (<aibeast-lan-ip>). aibeast may yet come back from
RMA, and two machines that have both held the same address is a debugging trap you would
be setting for yourself.
Phase 3 — do these before the network is the only way in
Both of these cost an incident last time by being retrofitted:
- Record the MAC address of the wired interface, and enable and persist Wake-on-LAN. When aibeast wedged on 21 July, the out-of-band path mattered more than anything on the box. Do it at build time.
- Confirm the smart plug can hard-cycle it. The plug was the recovery path on 21 July — the wedge cleared only when power was pulled. Verify that works now, deliberately, rather than discovering it under pressure.
Phase 3.5 — HARDWARE IDENTIFIED, AND A RISK TO CLEAR FIRST
aihydra is a BOSGAME BeyondMax on the Sixunited AXB35-02 board, Ryzen AI Max+ 395
w/ Radeon 8060S, 128 GB LPDDR5-8000, 2 TB Kingston NVMe, AMI BIOS 3.11 (2026).
BIOS UMA on Auto resolves to a 64 GB carveout — confirmed under Windows, which
reported 128 GB installed / 63.6 GB usable.
⚠ AXB35-02 is the board in ROCm issue #6182.
Every HIP workload loading a sizeable model reproduced a non-recoverable
Memory critical error by agent node-0 ... Reason: Memory in use. One investigator tried
14 configurations and got 14 failures; no workaround was found.
Why this is a risk to test rather than a reason to return it:
- Those failures were on AMI BIOS 1.07 (Sept 2025), and the write-up’s premise was that the vendor had shipped no updates since launch. This unit ships 3.11, dated 2026 — a different firmware generation, and proof the premise no longer holds.
- GMKtec’s EVO-X2 uses the same physical board and does not trigger the bug (BIOS v1.12), as do Framework Desktop and Beelink GTR9 Pro on the same silicon. The fault is firmware-attributed — specifically to UMA carveout, GTT and HSA queue handling — not inherent to the board.
So the ROCm smoke test comes FIRST, before preflight tuning, baselines or anything else. If it fails, every downstream decision is moot, and you want that answer while a return is still possible.
# after the OS + ROCm are in, before ANY tuning:
# load a model in the 60-70 GB class and watch for the fault
🔴 Test with a LARGE model — this is the part that is easy to get wrong. The fault triggers on the first sizeable GGUF upload. A 4 GB test model can load perfectly and give false confidence. Use something in the 60-70 GB class, which is where you will actually operate. On a 900 Mb line that is ~10 minutes of download to buy certainty.
Know the return window date. Not to use it — to know it. A firmware bug a vendor has not fixed is not something you can engineer around, and that deadline is the only thing in this whole plan that expires.
Phase 4 — verify the floor, then stop
./bench/preflight.sh
It checks kernel version, CWSR, firmware package and amdgpu-dkms — and is gated to Linux,
so it will refuse rather than false-pass. If preflight fails, fix it before installing
ROCm. Everything downstream assumes this floor holds.
Then capture the second number that cannot be recovered later:
Idle power with the OS up and no workload resident. ✅ Captured 2026-08-08: 10 W, against 1 W powered off. That pair is the calibration for the alarm below.
Phase 5 — the alarm aibeast never had
Build the Home Assistant automation on sensor.hardware_ai_hydra_power now, while the
baselines are fresh and before anything depends on the box:
Measured baselines (2026-08-08): 1 W powered off · 10 W idle with Ubuntu up and no model resident. Loaded figure still to capture.
Two thresholds, not one — and this is the improvement the numbers bought. The original sketch was a single “power fell below X” alarm. But aibeast’s two failures had different power signatures, and telling them apart took retrospective forensics:
| Condition | Meaning | Precedent |
|---|---|---|
| < ~15 W while a model should be resident | Inference died; the box is still alive | — |
| < ~3 W | The machine itself is gone | inc-0005, 23 Jul: collapsed to 0.5 W |
| Flat ~45 W, no response | Wedged after POST, needs a plug cycle | inc-0005, 21 Jul incident |
A single threshold would have fired for all three and told you nothing about which. Two thresholds separate “restart the server” from “the hardware is gone” at alert time, which is the whole difference between a five-minute fix and a twenty-hour silence.
inc-0005 was detected by absence — Warden failed over in 71 seconds and the warm-lane
canary said nothing for roughly 20 hours. The sensor data existed the entire time. Nobody
was looking at it. This automation is the whole lesson of that incident, and it takes
minutes to build on day one versus never getting built at all.
✅ BUILT AND VERIFIED — 2026-08-08
Ubuntu Server 26.04 LTS, no LVM, no encryption, whole 1.9 TB as one ext4 root.
Reachable as aihydra@<aihydra-lan-ip>.
Host floor — all four pass (bench/preflight.sh):
kernel 7.0.0-29-generic (≥6.18.4) · CWSR exported · no amdgpu-dkms ·
linux-firmware 20260319, not the ROCm-breaking 20251125.
Memory layout — the important result. BIOS UMA set to 1 GB, but that ALONE made
things worse: GTT defaults to half of RAM, so the GPU could reach only 62 GiB — less
than the 64 GiB the factory Auto carveout gave. Two parameters are required, not
one, because ttm.pages_limit is a global TTM ceiling that binds before
amdgpu.gttsize:
amdgpu.gttsize=106496 # megabytes = 104 GiB
ttm.pages_limit=27262976 # 4KiB pages = 104 GiB
Result: 1 GiB VRAM + 104 GiB GTT = 105 GiB GPU-reachable, with the OS still reporting 120 GiB available — GTT is a ceiling, not a reservation. Ling-3.0-flash at Q5_K_M (84.18 GB) now fits, which aibeast could never do.
104 GiB was chosen rather than the maximum deliberately: aibeast’s OOM panic was
amdgpu SVM restore plus a GTT-pinned llama-server, unkillable, and a maxed ceiling
both eases that failure and starves the page cache the disk-restore warm lane depends on.
Revisit with measurement, not by default.
Reproducibility lockdown. unattended-upgrades, apt-daily.timer and
apt-daily-upgrade.timer disabled; /etc/apt/apt.conf.d/99-aihydra-no-auto written so a
reinstall of the package does not silently re-enable them; linux-firmware,
linux-generic, linux-image-generic, linux-headers-generic all held. Kernel and
firmware are fingerprint fields — an unattended bump between two runs invalidates the
comparison with nothing in the data to show it.
SMART zero point — /dev/nvme0n1, Kingston OM8TAP42048K1-A00, fw P4ER3B31:
percentage_used 0% · power_on_hours 1 · power_cycles 20 · media_errors 0 ·
available_spare 100% · idle 32 °C. Genuinely new, not refurbished. This is the zero
point that makes a future wear rate measurable.
Defect found and fixed on first real use. preflight.sh crashed on
pgrep -c llama-server, which prints 0 AND exits non-zero when nothing matches, so
|| echo 0 appended a second line and the numeric test died. Counting lines instead is
immune to the exit status. The same class was fixed in grammar-ceiling.sh. Both scripts
had never met a Linux host before tonight.
✅ ROCm CLEARED — 2026-08-08, the question the build hung on
ROCm 7.1.0 (Ubuntu archive, no third-party repo, amdgpu-dkms not even in the archive)
runs a 73 GiB model on this board with zero faults. Issue #6182 does NOT affect this
unit — BIOS 3.11 clears what 1.07 did not. rocminfo enumerates gfx1151 (40 CU),
the CPU agent, and — unexpectedly — the XDNA2 NPU as aie2 / AIE-ML, a DSP agent visible
at the HSA level rather than only through FastFlowLM.
First numbers, stock llama.cpp @ 3653e6d, HIP, -ngl 999 -fa 1 --mmap 0:
| metric | result |
|---|---|
| pp512 | 324.07 ± 0.72 t/s |
| tg128 | 21.87 ± 0.00 t/s |
| SVM / HSA faults | 0 |
⚠ A REAL FAILURE FIRST, AND IT WAS NOT THE FIRMWARE BUG. The first attempt died with
thousands of amdgpu: SVM mapping failed, exceeds resident system memory limit. Cause:
mmap double-residency. The 73 GiB file sat in page cache while llama.cpp allocated the
same tensors again — 122 GiB of demand on a 122 GiB machine, 1 GiB free. --no-mmap plus
a dropped page cache fixed it completely.
This is a standing hazard on unified memory, not a one-off. On a discrete GPU the file
cache and VRAM are separate pools; here they compete for the same DIMMs. Any run that
mmaps a model close to half of RAM can hit it. amdgpu.no_system_mem_limit=1 exists as a
kernel escape hatch and is currently N — worth knowing, not yet needed.
The box survived it. No panic, no wedge, memory released cleanly on kill. That is
materially better than aibeast, which deadlocked unkillably on the adjacent failure
(amdgpu SVM restore + GTT-pinned llama-server).
OPEN — decode looks low and the memory layout is the suspect. 21.87 t/s against
aibeast’s recorded 36.5 and a bandwidth-derived ceiling of ~46 t/s (256 GB/s ÷ ~5.6 GB per
token at 10B active). Prefill is comparable (324 vs 354); it is specifically the
bandwidth-bound half that is down. Hypothesis: with a 1 GiB carveout everything is physically GTT, and GTT may carry an
access penalty on this silicon. Note the application does NOT see a small pool — ggml_cuda_init reports Total VRAM: 106496 MiB (104 GiB) and treats it as one
device memory space, so the layout works as intended from llama.cpp’s view. The
question is whether GTT-backed pages cost something VRAM-backed ones would not.
Competing explanations that must be excluded first: this run had no MTP, and
aibeast’s 36.5 came from a different config (cfg-0002) whose flags and quant have
not been matched. Do not treat 21.87-vs-36.5 as like-for-like until they are. If true
that is a genuine fit-versus-speed tradeoff. Next experiment: sweep the UMA/GTT split
and measure decode at each point — cheap, clean, and it decides the layout properly
instead of by assumption.
Deliberately NOT tonight
- No ROCm, no llama.cpp, no models. Those come after the floor is verified.
- No production restore. Warden stays on cloud
openai/gpt-5.5. Standing decision: the Strix Halo returns as a lab, not production, so reboots, flag changes and benchmarks stay free rather than disruptive. - No tuning. GTT size, UMA,
amd_iommuare all measured decisions with a baseline on either side. Tuning before the baseline exists destroys the ability to attribute the change — the same mistake as upgrading the kernel before capturing a pre-fix number.
Open decisions this raises
- OS and kernel path — which distribution, and mainline/HWE or stock, to clear ≥6.18.4.
- Patched or stock llama.cpp. Production ran our
.ckptsidecar fix (con-0001). With aibeast gone there is no cross-host comparison to break, so this is now a simpler question than the readiness checklist assumed — butbuild_commitis a config fingerprint either way, so it must be recorded, not defaulted. - Whether the NPU matters enough to forgo
amd_iommu=off. Untested on our hardware;clm-0013found the iGPU beat the NPU on both phases at 35B by roughly 4x, which weakens the case for protecting it.