An engineer enables a deep link power state and measures the board. Power goes up. The link really is idle most of the time, and the deep state really does draw a tenth of the active power. But each entry and exit spends energy relocking and retraining, and the idle periods on this board are short. Sleeping through a short gap costs more than staying awake through it.
How long must an idle period be before sleeping saves energy?
The obvious reasoning compares power: the sleep state draws less, so sleeping always saves. That ignores the transition. Entering and leaving takes time, and during it the link draws at least active power, often more (restarting PLLs, retraining). For a short enough idle period, the transition alone costs more than staying on for the whole period.
Let the link draw P_on when active, P_lp asleep, and spend T_tr in transitions at power P_tr. Over an idle period T:
Staying on costs P_on × T.
Sleeping costs P_tr × T_tr + P_lp × (T − T_tr).
They are equal at the break-even time T_be = (P_tr − P_lp) × T_tr / (P_on − P_lp).
Sleep through idle periods longer than T_be and you save; shorter, and you lose. With P_on = 100 mW, P_lp = 10 mW, P_tr = 150 mW and T_tr = 10 µs, T_be = 140 × 10 / 90 ≈ 15.6 µs. The break-even time is longer than the transition itself, because the transition draws more than active power.
The model computes the energy of sleeping against staying on for fixed idle periods, then applies a timeout policy (sleep only after τ idle microseconds) to 20,000 random idle periods on a lightly loaded link (mean idle 40 µs) and a busy one (mean 8 µs).
"""Break-even time of a link low-power state, and the timeout that decides when to enter it.
Staying on costs P_ON. Entering and leaving low power takes T_TR microseconds at a
higher transition power P_TR (relocking, retraining); while asleep the link draws P_LP.
For an idle period of T microseconds:
stay on: E_on = P_ON * T
sleep: E_lp = P_TR * T_TR + P_LP * max(0, T - T_TR) (a short idle still pays the full transition)
Break-even: the idle length at which both cost the same.
Then a timeout policy (sleep only after TAU idle microseconds) on random idle periods
(exponentially distributed, mean 40 us for a lightly loaded link, 8 us for a busy one):
energy saved against always-on, and how many idle periods end with a wake (each wake
delays the next request by the exit latency).
"""
import random
P_ON, P_LP, P_TR = 100.0, 10.0, 150.0 # mW
T_TR = 10.0 # us to enter and leave
PERIODS = 20000
def e_on(t):
return P_ON * t
def e_sleep(t):
return P_TR * T_TR + P_LP * max(0.0, t - T_TR)
def e_policy(t, tau):
if t <= tau:
return P_ON * t
return P_ON * tau + e_sleep(t - tau)
t_be = (P_TR * T_TR - P_LP * T_TR) / (P_ON - P_LP)
idles = [5, 10, 15, 20, 30, 50, 100, 200, 500]
print("idle period (us): " + " ".join(f"{t:6d}" for t in idles))
print("sleep/on energy: " + " ".join(f"{e_sleep(t) / e_on(t):6.2f}" for t in idles))
print(f"break-even time: {t_be:.1f} us")
taus = [0, 5, 10, 16, 30, 60, 120]
def run(mean, seed):
rng = random.Random(seed)
periods = [rng.expovariate(1 / mean) for _ in range(PERIODS)]
base = sum(e_on(t) for t in periods)
saved = [1 - sum(e_policy(t, tau) for t in periods) / base for tau in taus]
wakes = [sum(1 for t in periods if t > tau) / PERIODS for tau in taus]
return saved, wakes
saved, wakes = run(40.0, 1)
saved8, wakes8 = run(8.0, 2)
print("timeout (us): " + " ".join(f"{t:6d}" for t in taus))
print("saved, mean idle 40 us: " + " ".join(f"{s:6.2f}" for s in saved))
print("wakes, mean idle 40 us: " + " ".join(f"{w:6.2f}" for w in wakes))
print("saved, mean idle 8 us: " + " ".join(f"{s:6.2f}" for s in saved8))
assert abs(e_sleep(t_be) - e_on(t_be)) < 1e-6
assert e_sleep(10) > e_on(10) and e_sleep(20) < e_on(20)
assert all(a >= b for a, b in zip(saved, saved[1:])) and all(a >= b for a, b in zip(wakes, wakes[1:]))
assert saved8[0] < -0.5 and all(a <= b + 1e-9 for a, b in zip(saved8, saved8[1:]))
print(f"PASS: sleeping pays only for idle periods longer than {t_be:.1f} us; on a busy link sleeping at once costs energy, and a timeout limits the loss")It prints:
idle period (us): 5 10 15 20 30 50 100 200 500
sleep/on energy: 3.00 1.50 1.03 0.80 0.57 0.38 0.24 0.17 0.13
break-even time: 15.6 us
timeout (us): 0 5 10 16 30 60 120
saved, mean idle 40 us: 0.55 0.48 0.43 0.37 0.26 0.12 0.03
wakes, mean idle 40 us: 1.00 0.88 0.78 0.67 0.47 0.22 0.05
saved, mean idle 8 us: -0.90 -0.48 -0.26 -0.12 -0.02 -0.00 0.00
PASS: sleeping pays only for idle periods longer than 15.6 us; on a busy link sleeping at once costs energy, and a timeout limits the lossThree lessons in the numbers. Idle periods of 5 and 10 µs cost 3× and 1.5× the energy when slept through. On the lightly loaded link, sleeping at once saves the most energy, but every idle period then ends with a wake, and every wake adds exit latency to the next request; the timeout trades some energy for far fewer wakes. On the busy link, sleeping at once costs 90% more energy than never sleeping, and only a long timeout limits the loss.
Traffic | Policy |
|---|---|
Idle periods mostly much longer than T_be | Short timeout: sleep early, save most |
Idle periods mostly shorter than T_be | Long timeout or a lighter state: deep sleep loses energy |
Mixed or unknown | A timeout near T_be: it never spends more than about twice what the best possible choice would have |
Latency-sensitive | Limit wakes: a longer timeout, or a lighter state with a faster exit |
Protocol | Break-even in practice |
|---|---|
PCI Express ASPM | Each state's exit latency is reported; software enables a state only where it is acceptable, and L1 substates add deeper options for long idle periods (fact P34). |
USB 3.x | U1 and U2 are entered on inactivity timers, U2 with a longer timeout than U1 (fact S19). |
The opening board (illustrative) had idle periods of a few microseconds between DMA bursts. With the deep state enabled after a 1 µs timeout, the link spent most of its time in transitions. Moving the timeout to 20 µs, just above break-even, and using the light state for shorter gaps cut link power by 40% instead of raising it.
(200 − 20) × 9 / (200 − 20) = 9 µs: with the transition at active power, break-even equals the transition time.
Its idle periods (mean 8 µs) are mostly shorter than the 15.6 µs break-even time, so most sleeps cost more than they save.
Transitions cost energy, so sleeping saves only for idle periods longer than the break-even time.
T_be = (P_tr − P_lp) × T_tr / (P_on − P_lp); it exceeds the transition time when transitions draw more than active power.
Choose the timeout from the idle distribution and the wake latency the traffic tolerates.