Skip to content

cpu: recognise IRIX 6.5's idle loop and park it - #339

Merged
techomancer merged 1 commit into
techomancer:mainfrom
irix7:upstream/idle-65
Oct 27, 2026
Merged

techomancer merged 1 commit into
techomancer:mainfrom
irix7:upstream/idle-65

Conversation

@belikh

@belikh belikh commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

Summary

This ports the IRIX 6.5 idle-loop detector from Jupiter Belic's irix7/iris fork (PR #114, commits ee61088 and 52e5690) onto current upstream. With --features idle-pause, a settled IRIX 6.5 IP22 getty drops from ~100 % host CPU to ~1-2 %, and cold boots are not slowed.

Why the old detector never fired on 6.5

idleprof at a settled 6.5 IP22 getty (upstream build, xdm/amstart killed) 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. The capture:

  ffffffff880db080  1.0%  100%  addiu sp, sp, -16
  ffffffff880db058  1.0%  100%  lw at, -24164(zero)
  ffffffff880db098  1.0%  100%  jal 0x80daedc
  ffffffff880daedc  1.0%  100%  addiu sp, sp, -32
  ... (the rest of the run-queue scan at ~1.0% each)
  ffffffff88019fb0  8.4%  100%  bgtz a0, -1        <- the DELAY loop
  ffffffff88019fb4  8.4%  100%  subu a0, a0, a1

Its registers evolve every iteration (the run-queue scan rotates state), so the PC+GPR hash never repeats exactly. The same hash did match a 3-instruction device-poll loop seen during boot (lbu/andi/bne -3 waiting on a SCSI bit), which must keep executing — parking it stalled the boot. The idle loop has no contiguous window covering half the samples (the helpers are far away), which is why the detector clusters the samples instead.

Detector

The run loop calls sample after each ten-instruction group; sample records the PC every 32 calls, so a record is ~320 guest instructions and the ring of 32 covers ~10,000. update sorts the samples into PC clusters (consecutive PCs ≤256 bytes apart) and parks when one kernel cluster holds ≥12 of the 32 samples with ≥12 distinct PCs. 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.

That accepts IRIX 5.3's 14-instruction loop and 6.5's 89-instruction scheduler path while rejecting 2-instruction DELAY loops, 3-instruction device polls, the 8-instruction ll/sc lock spin and mixed work. The existing park rules are unchanged: interrupts enabled, a mask bit set, nothing pending, Compare armed; wake on any pending line; the masked-wake back-off (no re-park for ~20 ms after waking on a line the guest cannot take). Parking waits 60 s after the CPU thread starts (IRIS_IDLE_WARMUP_SECS overrides) so boot runs at full speed.

New monitor commands: idle on|off|status (runtime switch, park/sleep/wake counters, last window) and idleprof stats (the same counters).

The ci_clock ip7 unit tests now advance Count by retired cycles instead of sleeping, so the required --features ci_clock,idle-pause suite passes; no clock semantics change.

Measurements

Host: 6-core i5-8500T @ 2.1 GHz. Guest: IRIX 6.5 IP22, R4400, fresh sparse copy of the rig disk per run, nvram-rig.bin, headless, telnet forwarded; killall amstart; killall xdm after boot, then settle. Release build features: lightning,idle-pause unless noted.

measurement result
settled getty, lightning,idle-pause, 4 × 10 s 1 %, 1 %, 1 %, 2 %
wall-clock cold boot to login 35 s quiet host, 46 s under moderate load
lightning,ci_clock,idle-pause cold boot to login 52 s
ci_clock,idle-pause getty, 3 × 10 s 19 %, 16 %, 18 % (see note)
monitor cpu stop; cpu start resumes, parks again after the guest settles
guest date across a park correct

Note on ci_clock: guest time is retired instructions, so the timer handler is a much larger share of host time (~16-19 % here). The wall-clock build is the one the 1-2 % figure describes. A later wall-clock boot on the same host under load average ~14 (three other emulators running) took 101 s, so the 35 s figure is a quiet-host sample; parking itself was not the cause.

Not tested: IRIX 5.3, because this rig has no 5.3 image. Its 14-instruction loop fits the cluster rules and the park/wake mechanics are unchanged.

Tests

build command result
default cargo test --workspace 1348 passed, 0 failed
jitv2 cargo test --workspace --features jitv2 1830 passed, 0 failed
idle-pause cargo test --workspace --features idle-pause 1366 passed, 0 failed
ci_clock,idle-pause cargo test --workspace --features ci_clock,idle-pause 1366 passed, 0 failed

New tests cover the 6.5 window, distant helper calls, short device polls, a 2-instruction DELAY loop, user-mode loops, a moving window, the masked-wake back-off, and wake on Compare under both clock models. The masked-interrupt park test now samples the PC as the run loop does.

Provenance

This port is derived from Jupiter Belic's work in irix7/iris: PR irix7#114, commit irix7@ee61088 and docs correction irix7@52e5690. Taken from that work: the PC-cluster detector, the 60 s warm-up, the masked-wake back-off, the park statistics and idle/idleprof stats commands, the run-loop sampling points, and the ci_clock test adaptation. The capture and measurements were repeated here on upstream.

IRIX 6.5 never parked under idle-pause. The detector hashed PC+GPRs and
required an exact repeat, but 6.5's idle path is a ~470-byte scheduler loop
(~89 instructions) with calls to spl and the ll/sc lock and stores to kernel
globals; its registers evolve every iteration, so the hash never repeated. It
also matched short device-poll loops (lbu/andi/bne -3 on a SCSI bit) that
must keep running.

Replace it with a PC-cluster sample. The batch loop calls sample after each
ten-instruction group; sample records the PC every 32 calls (~320
instructions per record, ~10,000 per ring of 32). update sorts the samples
into PC-space clusters and parks when one kernel cluster holds at least 12
samples with 12 distinct PCs. User-mode samples are tolerated up to a quarter
of the ring. Short DELAY/poll loops, the ll/sc lock spin and user code are
never parked. All previous rules remain: IE/IM, pending-line wake,
masked-wake back-off, Compare armed. Parking starts 60 s after the CPU thread
starts (IRIS_IDLE_WARMUP_SECS overrides) so boot is not sliced.

idle on|off|status switches parking at runtime and reports counters;
idleprof stats prints the park counters.

The ci_clock ip7 unit tests now advance Count by retired cycles, so the
required ci_clock,idle-pause suite passes.

Measured on IRIX 6.5 IP22 (R4400, fresh disk, lightning,idle-pause build):
settled getty 1-2% host CPU; cold boot 35 s. ci_clock,idle-pause boot 52 s;
its getty 16-19% (guest time is retired instructions). IRIX 5.3 not tested
(no image).
@techomancer
techomancer merged commit 092a6ee into techomancer:main Oct 27, 2026
14 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants