Chapter 05 · Reps

The Budget That Governs Everything — Reps

← Back to Chapter 5

Chapter 5 — Reps

Conditioning, not grading. This week’s reps are the energy reflexes: the operating-point table, the efficiency knee, break-even residency, the battery budget, and the difference between the number a short run reports and the number a hot device delivers.

Ground rules:

  1. Type every command and every snippet yourself. No copy-paste. Your hands have to learn E = P × t and Wh = mAh × V / 1000 the way they learned to touch-type, because you will be doing this arithmetic in a design review with nothing but a whiteboard.
  2. Run everything. Compile code/energy_model.cpp. Run code/throttle_analysis.py and code/battery.py. Reading about a knee is not the same as watching a column turn around.
  3. Predict before you measure. Every rep below asks for a written prediction first. Then run it. The gap between the two is the entire lesson; a rep where you guessed right taught you less than one where you were wrong and found out why.
  4. AI policy — explain, never source. You may use a model to explain the cubic approximation, break-even residency, what a governor is, or why voltage is squared. You may not use one for a number. Every thermal design power, battery capacity, nominal cell voltage, operating point, or device figure comes from a vendor specification page, an architecture reference manual, or your own measurement — and you cite it. A model will invent a specific, confident, wrong sustained-power figure in a tone indistinguishable from a datasheet. End any AI-touching rep with an honest one-line AI usage note.
  5. Every rep here works on Workbench B. Steps that need real hardware, a battery, or a phone are marked optional and always have a non-device path. See Appendix A.

Record every run in the measurement log format from Appendix C — what, on what, how many repetitions, median, dispersion, conditions. You will need it for the project.


Reps 1–3: The Power Equation and the Knee

Rep 1 — Derive the operating-point table by hand and find the knee

No tools. Paper and head only, first. Use these three operating points from the model in §5.3, a work quantum of N = 3 × 10⁹ cycles, a switched-capacitance constant k = 1.2 × 10⁻⁹ W/(V²·Hz), and a platform power of 0.9 W paid every second the task runs:

f (MHz)Vleakage (W)
12000.780.07
20000.930.14
30001.120.34

For each point compute, by hand: run time t = N/f, dynamic energy E_dyn = k·V²·N, static energy E_stat = (leakage + platform)·t, and total joules per task. Predict which of the three is cheapest before you finish the arithmetic. Then check yourself:

g++ -std=c++17 -O2 -o energy_model code/energy_model.cpp
./energy_model

Write down: your three totals, the program’s, and one sentence explaining why the f cancelled out of the dynamic-energy term. If that cancellation does not feel obvious, redo the algebra until it does — it is the single most important line in the chapter. Then note where your three-row table put the cheapest point and where the program’s seven-row table puts the actual knee. They are not the same operating point, and the reason is not physics. It is sampling resolution: a coarse sweep can miss a minimum entirely. Say in one sentence what that implies for anyone characterising real silicon from three data points.


Rep 2 — Move the efficiency knee on purpose

The knee is not a property of the core. Prove it.

./energy_model                     # baseline: 0.9 W platform
./energy_model --platform 3.0      # screen lit, radio active
./energy_model --platform 0.2      # deep-background, nothing else awake
./energy_model --window 1.2        # a hard 1.2 s deadline

Predict first, for each of the last three: does the knee move up, down, or stay? By roughly how much? Then run them and fill in a small table of --platform versus knee frequency versus J/task.

Write down: the direction the knee moves as platform power rises, in one sentence of physical reasoning (not “because the program said so”). Then answer the design question: a wearable’s platform power is tiny and its idle state is deep. Where does that put its knee relative to a phone’s, and what does that imply about how aggressively a wearable should clock?


Rep 3 — Read your machine’s governor, its available frequencies, and its idle-state ladder

Everything in §5.4 and §5.5 is exposed by your operating system. Go look.

# Linux — the governor, the OPP menu, and where the core is right now
cd /sys/devices/system/cpu/cpu0/cpufreq
cat scaling_available_governors scaling_governor
cat scaling_available_frequencies scaling_cur_freq

# Linux — the idle-state ladder: name, exit latency (us), required residency (us), use count
for s in /sys/devices/system/cpu/cpu0/cpuidle/state*; do
  printf '%-10s lat=%-8s resid=%-8s used=%s\n' "$(cat $s/name)" \
    "$(cat $s/latency)" "$(cat $s/residency)" "$(cat $s/usage)"
done

On macOS the tunables are not exposed; use sudo powermetrics -n 3 -i 1000 --samplers cpu_power to watch frequency and package power instead. On a cloud dev box you may see a single governor and a truncated ladder — that is itself a finding, and you should say so rather than skipping the rep.

Predict first: how many idle states do you expect, and will the required residency be larger or smaller than the exit latency for each? Then run it. Write down: the deepest state’s latency and residency, and one sentence on why residency is always the larger of the two.


Reps 4–6: Energy, Not Power

Rep 4 — Joules per task on your own machine, and the number you cannot measure

Time a fixed task honestly, then try to price it.

# A fixed quantum of work, timed. Repeat 7 times; report the median.
for i in $(seq 1 7); do
  /usr/bin/time -p python3 -c "
import math
x = 0.0
for i in range(3_000_000):
    x += math.sqrt(i % 1000 + 1)
print(x)
" 2>&1 | grep real
done

Now try to turn seconds into joules. On Linux, if your machine has a battery, cat /sys/class/power_supply/BAT*/power_now reports instantaneous draw in microwatts; on macOS, sudo powermetrics --samplers cpu_power -n 1 reports a package power estimate. On a cloud box you will find neither.

Write down: your median run time with its dispersion, the power figure you used (and exactly where it came from), the resulting joules, and — the real point of this rep — a one-sentence honest statement of which of those two numbers you actually measured and which you borrowed. Time is cheap and reliable to measure. Power is not. That asymmetry is why Week 8 spends a whole chapter on measurement honesty. AI usage: none. Do not ask a model for your machine’s power draw.


Rep 5 — Break-even residency: is this nap a net loss?

Pure arithmetic, done three times.

A block can enter a deep sleep state. Entering and leaving costs 3 mJ of transition energy in total. While asleep it saves 0.4 W relative to staying awake and idle.

  1. Compute the break-even residency: T = E_transition / ΔP.
  2. The scheduler predicts a 4 ms gap. Net gain or net loss, and by how many millijoules?
  3. The scheduler predicts a 40 ms gap. Same two questions.
  4. Now the hard one: a shallower state costs 0.2 mJ to enter and saves 0.15 W. Which of the two states should the kernel pick for the 4 ms gap, and which for the 40 ms gap? Show the arithmetic for all four combinations.

Write down: the four numbers and one sentence naming another mechanism you have already met that has exactly this shape (hint: Chapter 3 has one, and Chapter 2 has another). Then say what happens to the answer if the governor’s prediction of the gap is wrong by 5×.


Rep 6 — The battery budget, from mAh to hours

python3 code/battery.py                                  # the profile menu
python3 code/battery.py --profile reading
python3 code/battery.py --profile video-streaming
python3 code/battery.py --profile sustained-inference

Predict first, before you run any of them: for reading, which subsystem do you think dominates the budget — the SoC or the display? Write your answer down. Most students get this wrong, and being wrong here is worth more than being right.

Then do the conversion by hand for a battery you can actually cite: find a real device’s capacity in mAh and its nominal cell voltage on the manufacturer’s own specification page, and compute watt-hours and joules yourself. If you cannot find the nominal voltage from a primary source — and you often cannot — say so and use the mAh figure only structurally. That is the correct professional move, and inventing a plausible 3.85 V is not.

python3 code/battery.py --mah <cited> --volts <cited> --profile video-streaming

Then find the crossover by hand before you check it. --draw replaces one subsystem’s figure in the chosen profile — the name has to be a subsystem that profile already has, or the program will refuse and tell you which ones it knows:

python3 code/battery.py --profile reading --draw display=0.30

Write down: the cited capacity with its source URL, the computed watt-hours and joules, the dominant subsystem in each profile, and one sentence on how far the --draw display=... override would have to fall before the SoC became the dominant actor in the reading profile.


Reps 7–9: Heat, Throttling, and the Honest Number

Rep 7 — Find the throttle onset and compute the sustained-to-peak ratio

python3 code/throttle_analysis.py

Predict first: looking only at the fact that this is a fifteen-minute run of a phone-class SoC, at roughly what second do you expect throttling to begin, and what sustained-to-peak ratio do you expect? Commit to two numbers. Then run it.

Now vary the analysis window and watch the story change:

python3 code/throttle_analysis.py --window 30  --tail 120
python3 code/throttle_analysis.py --window 120 --tail 600

Write down: the throttle onset, the sustained clock and power, the sustained-to-peak ratio, and — this is the graded habit — one sentence on how much the reported ratio moved when you changed --window and --tail, and what that tells you about anyone who quotes a ratio without stating their window. Note also, explicitly, that thermal-soak.csv is synthetic teaching data and may never be cited as a measurement of any product.


Rep 8 — Run your own ten-minute soak and watch the clock fall

Type this yourself, calibrate it, then run it for real.

# soak.py — a portable sustained-load probe. Calibrate CHUNK first (below),
# then run one copy per core and watch delivered chunks/s over ten minutes.
import math, time

CHUNK = 2_000_000          # calibrate: aim for roughly 0.5-1.0 s per chunk
DURATION = 600             # seconds

def work(n):
    x = 0.0
    for i in range(n):
        x += math.sqrt(i % 1000 + 1)
    return x

t0 = time.perf_counter(); mark = t0; done = 0
while time.perf_counter() - t0 < DURATION:
    work(CHUNK); done += 1
    now = time.perf_counter()
    if now - mark >= 10.0:
        print("%7.1fs  %7.2f chunks/s" % (now - t0, done / (now - mark)))
        done = 0; mark = now

Calibrate first. Time a single chunk and adjust CHUNK until one chunk takes roughly half a second to a second on your interpreter — the difference between Python versions here is large:

python3 -c "
import time, math
def work(n):
    x = 0.0
    for i in range(n): x += math.sqrt(i % 1000 + 1)
t = time.perf_counter(); work(2_000_000)
print('%.3f s per 2M-iteration chunk' % (time.perf_counter() - t))"

Then launch one copy per core (for i in $(seq 1 $(nproc)); do python3 soak.py > soak-$i.txt & done on Linux; use sysctl -n hw.ncpu on macOS) and let it run the full ten minutes. Watch the chunks/s column.

Predict first: will your machine’s delivered rate fall? If so, at roughly what second, and to what fraction of its opening rate? Write both numbers down before you start.

Write down: your opening rate, your final rate, the ratio, the second at which the rate first dropped, and the conditions — plugged in or on battery, lid open or closed, ambient, machine on a desk or on a soft surface. If your rate did not fall, that is a legitimate and interesting result: say so, and give the two most likely reasons (a machine with real cooling headroom, or a workload too light to reach the envelope). On a shared cloud box, note that you cannot distinguish your own throttling from a noisy neighbour — a limitation you must state rather than paper over.


Rep 9 — Report the same sixty-second run three honest ways

Take the soak data you just produced in Rep 8 (or thermal-soak.csv if Rep 8 produced no throttling) and write three one-line performance claims about it, each of which is completely true:

  1. A claim that makes the machine look as good as honesty allows.
  2. A claim that makes it look as bad as honesty allows.
  3. The claim you would actually publish.

Each must state its conditions. None may contain a false number.

Write down: the three claims, then two sentences: which one a buyer needs, and which one a product engineer sizing a workload needs — they are not always the same claim. Then name the specific piece of information whose omission made claim (1) possible. That omission is the week’s apologetic point in engineering form.


Reps 10–11: The Platform in the Loop

Rep 10 — Read the thermal ladder and the headroom forecast

Work from the API in §5.11. An application is generating tokens from an on-device model and polls getThermalHeadroom(10) every second. It reads, in order: 0.62, 0.71, 0.83, 0.94, 1.02.

Write down, for each reading: what the platform is forecasting, and what the application should do at that step — nothing, reduce quality, defer discretionary work, or stop. Justify the step at which you first act, and explicitly say why waiting for THERMAL_STATUS_SEVERE would have been too late (your answer must mention the thermal time constant from §5.9).

Then the architecture question: name three concrete pieces of work in that token-generation scenario that the application knows are discretionary and the governor does not.

Optional — Workbench D. On an Android device with developer options and the debug bridge:

adb shell dumpsys thermalservice

Read the current status and the reported temperatures, run something heavy, and read it again. Never required; if you do it, log the device and the ambient conditions.


Rep 11 — Re-read Chapter 4’s accelerator claim under a sustained budget

A placement study from Chapter 4 concluded: “run the model on the NPU; it is 3× faster than the CPU path and uses a third of the energy per inference.” Assume both halves of that claim are correctly measured on a cold device.

Write down the answers to these four, in order:

  1. What does that claim tell you about a workload that runs for ninety seconds instead of one inference?
  2. Which of The Four Questions does it answer, and which does it leave open?
  3. Using the sustained/peak ratio you found in Rep 7, restate the claim in a form that would survive a ten-minute run.
  4. Name the one measurement you would take on real hardware to decide whether the original claim holds under sustain — and say what result would falsify it.

This is the exact reasoning the project grades. Do it carefully now and the project’s hardest section is already drafted.


Done? One Last Thing.

The energy verdict in miniature — this is the project’s graded core, at one-tenth scale.

You are given a delivered-work target: the task from Rep 1, run 400 times, finished within a 30-minute window, on a device whose deep-idle draw is 0.05 W. Choose an operating policy — race-to-idle at the top point, run at the knee, or something in between — and defend it.

  1. Do the arithmetic. Use ./energy_model with the platform power you think is right for a device whose screen is off between tasks, and state that assumption explicitly. Compute total joules for at least three candidate policies.
  2. Convert to the battery. Use python3 code/battery.py to turn your winning policy’s joules into a share of a real, cited battery’s watt-hours.
  3. Check it against heat. Using code/thermal-soak.csv and Rep 7’s numbers, say whether your chosen policy is even sustainable for 30 minutes, or whether the device would throttle out from under it — and if it would, revise the policy and redo step 1.
  4. Write the verdict in about 150 words. State the policy, the joules, the assumption you are least sure of, and the single measurement that would change your mind.

Keep this write-up. It is the shape of the report.docx the project asks for — you have already drafted its spine.


Up next: Project 5 — Project 5: The Energy and Thermal Study.