← etch

Synchronization · ARMv8-A · silicon → instruction set

Why a sleeping core
is a faster core.

A core stuck in a spinlock burns full power to learn nothing. WFE turns that hot loop into a quiet sleep that the lock-releaser wakes for free. WFI is its cousin for the idle loop. Below, each mechanism is built from the physics up — every animation matches the real ARM architecture, nothing invented.

01

The power tax: a busy core that does nothing still pays

Dynamic power in CMOS is P = α·C·V²·f. The term that matters here is α, the activity factor — the fraction of transistors that toggle each cycle. A core spinning in while(locked){} toggles its whole pipeline every cycle to re-confirm a value that hasn't changed. Same energy, zero useful work. The escape is to gate the clock: stop toggling, and α (and with it dynamic power) collapses to zero, leaving only static leakage. That is the entire reason WFI/WFE exist.

scope · core power vs. activity
toggle to watch power move
Busy-spinning: clock toggling, pipeline active every cycle. α ≈ 0.9 · dynamic power near maximum, all of it wasted re-checking the lock.

To your bones: the lock isn't changing while you spin, so every one of those watts buys nothing. Gating the clock is free performance — but a gated core is deaf. We now need a way to wake it. Hold that thought.

02

The race: why shared data needs a lock at all

Two cores both do counter++. That single line is really read → add → write — three steps. If the steps interleave, an update is silently lost. A lock forces the three steps to happen indivisibly. Step through both worlds and watch the counter.

scope · two cores, one counter
No lock. Press Step to interleave the two cores one micro-step at a time.

To your bones: correctness demands that "test the lock and take it" be one atomic, uninterruptible act. The hardware that delivers that atomicity is the exclusive monitor — next.

03

The exclusive monitor: how silicon makes a read-modify-write atomic

ARM's atomicity is optimistic. LDAXR (load-acquire exclusive) reads the lock and arms a per-core global monitor for that address (state: Open → Exclusive). STXR (store-exclusive) only commits if the monitor is still Exclusive; otherwise it fails and returns 1, and you retry. Crucially, any write to the watched address clears every other core's monitor (Exclusive → Open). Watch two cores race — and note the monitor-clear, because it is the seed of the wake-up mechanism later.

scope · LDAXR / STXR · global monitor
Both cores want the lock. Press Step to watch the optimistic dance.

To your bones: STXR succeeding is hardware proof that nobody touched the address since your LDAXR. And the monitor-clear that fails the loser's store is the same physical event that will later ring a sleeping core's doorbell.

04

Cache-line bouncing: the naive lock saturates the fabric

Even with atomics, how you spin matters. Test-and-Set hammers the lock with an atomic write every cycle — and an atomic write needs the cache line in a writable (Modified) state, owned by exactly one core. So the line ping-pongs around the ring, each grab invalidating everyone else. Test-and-Test-and-Set spins on a plain load instead; a load only needs a Shared copy, so every core reads from its own L1 in silence. Toggle and watch the interconnect traffic counter.

scope · 4 cores · 1 lock line · MESI traffic
watch the traffic meter
Test-and-Set: every waiter writes the line every cycle. The line bounces core→core, invalidations flood the interconnect. Throughput collapses as cores increase.

To your bones: TTAS kills the traffic, but the core is still awake, still toggling its load loop, still paying chapter 1's power tax and stealing SMT issue slots. The last move is to stop spinning entirely — and sleep.

05

WFI vs WFE: two ways to sleep, two ways to wake

Both park the core in a low-power state. The difference is the wake set. WFI wakes only on an interrupt (it ignores events entirely). WFE wakes on everything WFI does plus a system event, tracked by a one-bit sticky Event Register. And the safety detail that makes lock code race-free: if the Event Register is already set when you execute WFE, it clears the bit and returns immediately — it never sleeps. Press the signals and watch each core.

scope · WFI core · WFE core · event register
Both cores are parked. SEV sets the WFE core's Event Register and wakes it; the WFI core ignores it. IRQ wakes both.

To your bones: WFI = "wake me when the outside world has work" (the idle loop). WFE = "wake me when a peer signals me" (the lock loop). The sticky register means a wake-up that arrives a nanosecond too early is never lost.

06

The full WFE spinlock: every layer at once

Now we assemble it. Core A holds the lock and runs its critical section. Cores B and C tried to acquire, saw it held, and executed WFE — they're asleep at leakage-only power, monitors armed (Exclusive). When A releases with STLR lock,#0, that single store clears B's and C's monitors, which generates an event for each — no explicit SEV needed. They wake, re-run acquire; one wins, the other's STXR fails and it sleeps again. Step through the whole machine.

scope · 3 cores · WFE acquire/release · monitor-clear wake
Core A holds the lock. B and C are asleep in WFE. Press Step to release the lock and watch the wake-up cascade.
// AArch64 — the canonical WFE spinlock
acquire:
    LDAXR  w1, [lock]      // load-acquire exclusive → arms global monitor
    CBNZ   w1, wait        // lock held? go to sleep
    STXR   w2, w0, [lock]  // try to take it
    CBNZ   w2, acquire     // store-exclusive failed → retry
    // --- lock owned ---
wait:
    WFE                    // sleep at leakage-only power until an event
    B      acquire         // woken → re-check

release:
    STLR   wzr, [lock]     // store-release 0 → clears waiters' monitors → wakes them
Σ

The two instructions, side by side

AxisWFI — Wait For InterruptWFE — Wait For Event
Wakes onInterrupts, debug, resetAll of WFI's sources + events: SEV / SEVL, the timer event stream, and a monitor Exclusive→Open transition
Event RegisterIgnored — SEV cannot wake itConsulted & cleared. If already set, returns immediately (lost-wakeup guard)
Canonical useOS idle loop; deep power-downSpinlocks; short inter-core waits
Power-state depthGood candidate for retention / power-gate (long waits)ARM advises shallow states — WFE waits are short and snoop-sensitive
Mental model"Wake me when the world has work""Wake me when a peer signals me"

The whole chain in one breath: physics taxes every toggle (ch.1) → so we gate the clock and need a wake mechanism → shared data needs atomicity (ch.2) → delivered by the exclusive monitor (ch.3) → whose monitor-clear also doubles as a wake event → naive spinning floods the fabric (ch.4) → TTAS quiets it but still burns power → WFE sleeps and is woken precisely by that monitor-clear event (ch.5) → giving the full, near-free spinlock (ch.6). WFI is the same idea pointed at interrupts instead of events.