Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,25 @@ hashes are given where a change is easiest to understand by reading the commit.

## October 2026

### Idle parking

- **IRIX 6.5's idle loop is recognised and parked.** With `--features
idle-pause`, a settled 6.5 IP22 getty now uses ~1-2 % host CPU instead of
~100 %. The previous detector hashed PC and registers and required an exact
repeat; 6.5's idle path is a ~470-byte scheduler loop whose registers
evolve every iteration, so it never fired, while the same hash matched
short device-poll loops that must keep running. The replacement samples the
PC every 32 sample calls (about 320 instructions in the batch loop), groups
the samples into PC-space clusters, and parks when one long kernel cluster
dominates the ring; short countdown/device-poll loops and user-mode code
are never parked. Parking waits 60 s after CPU start
(`IRIS_IDLE_WARMUP_SECS` overrides) so boot is not slowed.
- **New monitor commands.** `idle on|off|status` switches parking at runtime
and reports park/sleep/wake counters; `idleprof stats` prints the park
counters.
- The `ci_clock` unit tests that materialise Count now advance it by retired
cycles, so `--features ci_clock,idle-pause` passes.

### JIT v2

- **FPU integer conversions are compiled inline.** `CVT.W/L.S/D`,
Expand Down
3 changes: 2 additions & 1 deletion FEATURES.md
Original file line number Diff line number Diff line change
Expand Up @@ -483,7 +483,8 @@ and offline-tool controls are included so they are not mistaken for GUI settings
| `IRIS_REX3_TRACE` | Trace REX3 GFIFO and CPU accesses from board start to this path (`gputrace` builds). | [src/dev/ng1/rex3_trace.rs](src/dev/ng1/rex3_trace.rs) |
| `IRIS_NO_EXIT_ON_POWEROFF` | Any presence prevents process exit on guest power-off/CI quit; set by GUI. | [src/ci.rs](src/ci.rs) |
| `IRIS_NO_FETCH_VERIFY` | 1 suppresses fetchverify checks in a fetchverify build. | [src/cpu/mips_exec.rs](src/cpu/mips_exec.rs) |
| `IRIS_NO_IDLE` | Any presence disables idle parking. | [src/cpu/idle_park.rs](src/cpu/idle_park.rs) |
| `IRIS_NO_IDLE` | Any presence disables idle parking at startup; `idle on` re-enables it. | [src/cpu/idle_park.rs](src/cpu/idle_park.rs) |
| `IRIS_IDLE_WARMUP_SECS` | Seconds after CPU start before idle parking engages (default 60; 0 disables the warm-up). | [src/cpu/idle_park.rs](src/cpu/idle_park.rs) |
| `IRIS_NO_INLINE_MEM` | Any presence disables JIT inline memory emission. | [src/cpu/jitv2/codegen.rs](src/cpu/jitv2/codegen.rs) |
| `IRIS_NO_JIT` | Any presence disables the REX3 shader JIT and the IMPACT raster JIT; does not select the MIPS engine. | [src/dev/ng1/rex3.rs](src/dev/ng1/rex3.rs) |
| `IRIS_OPT_SPEED` | Presence selects speed optimization in offline PCP/corpus measurements. | [src/bin/jitv2_pcp_dump.rs](src/bin/jitv2_pcp_dump.rs) |
Expand Down
10 changes: 10 additions & 0 deletions HACKING.md
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,16 @@ when the guest is in its idle loop. A producer that adds work, or a device
that raises an interrupt, unparks the thread it is waiting on. See
`clanker/perf/` for what went wrong each time a parking rule was missed.

The idle detector samples the guest PC every 32 sample calls (about 320
instructions in the batch loop) and parks only when one long kernel cluster of
code dominates the sample ring (at least 12 of 32 samples and 12 distinct PCs,
no user-mode majority), with interrupts enabled, a mask bit set, nothing
pending and Compare armed. That accepts IRIX 5.3's 14-instruction loop and
6.5's ~89-instruction scheduler path while rejecting short DELAY and
device-poll loops. Parking starts 60 s after the CPU thread starts
(`IRIS_IDLE_WARMUP_SECS` overrides), so boot runs at full speed. The monitor's
`idle on|off|status` controls and reports it.

## 5. Locks

The rules, in order of importance:
Expand Down
41 changes: 40 additions & 1 deletion clanker/perf/idle-pause-work.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,12 @@ break out as soon as an unmasked interrupt is pending. `IRIS_NO_IDLE` disables i
dropped from **~100 % to ~2 %** (headless), the system stayed responsive (serial
input echoes → wake-on-IRQ works) and the clock stayed correct (`date` in shell).

### Detector — WORKING (architectural-state repeat, k0/k1 excluded)
### Detector — architectural-state repeat (SUPERSEDED, see below)

> **Superseded 2026-10-27.** The hash below never fires on IRIX 6.5, whose idle
> path is a long scheduler loop with evolving registers, and it *does* match
> short device-poll loops that must keep running. The PC-cluster detector now
> in `src/cpu/idle_park.rs` replaces it; see "Detector — PC-cluster sample".

The crux was distinguishing the kernel idle loop from a busy **delay loop**:
- IRIX boot calls a calibrated `DELAY()` at `0x88003d70`: `bgezl v1,-1; subu v1,v1,v0`
Expand Down Expand Up @@ -207,3 +212,37 @@ targets.
**Other TODO:** the v1 JIT path that bypassed this run loop entirely has been
removed. Whether/how `jitv2` (`--features jitv2`, a from-scratch region compiler)
needs its own idle-park hook has not yet been investigated.

### Detector — PC-cluster sample (current, 2026-10-27)

`idleprof` at a settled IRIX 6.5 IP22 getty shows the idle path is not a tight
branch: it is a ~470-byte scheduler loop (0x880daedc..0x880db0b4, ~89
instructions) with calls to `spl` and the ll/sc lock and stores to kernel
globals. Its registers evolve every iteration (the run-queue scan rotates
state), so PC+GPRs never repeats exactly — the old detector could not fire.
It also matched a 3-instruction device poll seen during boot
(`lbu/andi/bne -3` on a SCSI bit), which must keep executing.

The replacement samples the guest PC every 32 sample calls: the batch loop
calls `sample` after each ten-instruction group, so that is about 320 guest
instructions per record and ~10,000 per ring. `update` sorts the samples into
PC-space clusters (consecutive PCs <=256 bytes apart) and parks when one
**kernel** cluster holds at least 12 of the 32 samples with 12 distinct PCs.
That rejects the 2-instruction DELAY loop, 3-instruction device polls, the
8-instruction ll/sc lock spin and mixed work, while accepting the 5.3
14-instruction loop and 6.5's 89-instruction scheduler path. User-mode samples
are allowed up to a quarter of the ring (a syscall wake runs a few user
instructions between kernel stretches), but a user-dominated ring is refused.

The earlier safety rules remain: no parking with IE=0 or every mask clear,
wake on any pending line and on `running=false`, the masked-wake back-off
(no re-park for ~20 ms after waking on a line the guest cannot take), and no
park before Compare is armed. Parking waits 60 s after the CPU thread starts
(`IRIS_IDLE_WARMUP_SECS` overrides) so boot runs at full speed. `idle
on|off|status` and `idleprof stats` expose the switch and counters.

Measured on the fork's rig (6-core i5-8500T, IRIX 6.5 IP22, R4400, fresh
disk): a settled getty with the `lightning,idle-pause` build uses 1-2 % host
CPU; the wall-clock cold boot is 35 s; `ci_clock,idle-pause` boots in 52 s and
its getty runs at ~16-19 % (guest time is retired instructions, so the timer
handler is a larger share of host time). IRIX 5.3 was not tested (no image).
3 changes: 2 additions & 1 deletion debug.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,8 @@ exception of that class is taken. `ex tlb on` stops on every TLB exception.
| `undo clear` / `undo resize <n>` | Clear / resize the undo history **[DEV]** |
| `debug <on\|off\|file <path>>` | Print every executed instruction, or write them to a file **[DEV]** |
| `trace start <path>` / `trace stop` / `trace status` | Record full per-instruction architectural state to a file **[DEV]** |
| `idleprof <on\|off\|report [n]>` | Sample the PC to find idle and spin loops (`idle-pause` builds) |
| `idleprof <on\|off\|report [n]\|stats>` | Sample the PC to find idle and spin loops (`idle-pause` builds); `stats` prints park counters |
| `idle <on\|off\|status>` | Turn idle parking on or off at runtime, or show park counters and the detector's last window (`idle-pause` builds) |
| `instrstats [report\|clear\|dump]` | Per-instruction decode/execute counters (`--features instr_stats`) **[DEV]** |

The undo buffer tracks register changes and memory writes. It does not
Expand Down
Loading
Loading