Worked examples — Neural processing units (NPUs)
This page drills Neural processing units (NPUs) through every case class the topic can throw at you: full arrays, half-filled arrays, tiny degenerate layers, the pipeline fill/drain edge, the memory-bound limit, and precision trade-offs. We build each number from scratch — no formula and no jargon is used before we say what it means, right here on this page.
The scenario matrix
Before working anything, here is the map of every case an NPU throughput/efficiency problem can land in. Each worked example below is tagged with the cell(s) it covers.
| Cell | Case class | What makes it tricky | Example |
|---|---|---|---|
| A | Full array, perfect fit | The "textbook" peak — baseline | Ex 1 |
| B | Partial columns/rows used | Utilisation drops below 100% | Ex 2 |
| C | Layer bigger than array (tiling) | One pass isn't enough; loop the array | Ex 3 |
| D | Pipeline fill/drain overhead | Small layer → latency dominates throughput | Ex 4 |
| E | Degenerate input (, or ) | Dot product of length 1; array mostly idle | Ex 5 |
| F | Memory-bound limit (roofline) | Compute is fast but data can't arrive | Ex 6 |
| G | Precision trade (int8 vs fp32) | Same silicon, different MAC count | Ex 7 |
| H | Real-world word problem | Translate a phone-chip spec into numbers | Ex 8 |
| I | Exam twist (solve for unknown) | Given TOPS, find the missing clock/size | Ex 9 |
The three quantities we reuse everywhere
Every example plugs into the same three ideas. We state each in plain words before using its symbols.
One dataflow we must define before Example 4: weight-stationary
Now the scenarios.
Example 1 — Cell A: full array, perfect fit
Recall Forecast first
Guess before reading: is it closer to 1 TOPS, 100 TOPS, or 10000 TOPS? Your guess ::: About 131 TOPS — width, not clock, does the work.
Step 1 — Count the PEs. multiply-accumulators. Why this step? Peak throughput is "everyone works at once," so we first count how many calculators exist.
Step 2 — One MAC = two ops. Each PE does 1 MAC/cycle = 2 ops/cycle. Why this step? TOPS counts operations, and the factor of comes from mult + add (defined above).
Step 3 — Multiply by clock. Why this step? The clock is "how many cycles per second," so ops/s = ops-per-cycle × cycles-per-second.
Step 4 — Convert to TOPS ( ops/s).
Recall Verify
A single-MAC CPU at 3 GHz does ops/s. Ratio — the array is ~22000× wider-per-second. Units check: (PEs)(ops/PE/cycle)(cycles/s) = ops/s. ✓
Example 2 — Cell B: partial array (utilisation < 100%)
Recall Forecast
If half the PEs are dead weight, effective throughput should be… ::: half of peak.
Step 1 — Peak (all PEs). Why this step? Peak is fixed by the hardware, not the layer — it's the ceiling.
Step 2 — How many PEs are busy? Only 64 columns are loaded → of PEs active. Why this step? Utilisation = busy ÷ total; an unloaded column contributes zero MACs no matter the clock.
Step 3 — Utilisation.
Step 4 — Effective TOPS. Why this step? Real speed = ceiling × fraction of ceiling actually reached.

Recall Verify
The figure shows 64 lit columns, 64 dark → lit fraction . Effective = 32.8 TOPS, exactly half of 65.5. ✓
Example 3 — Cell C: layer bigger than the array (tiling)
Recall Forecast
The output is . How many output blocks fit in it? ::: tiles.
Step 1 — Total MACs from the formula. Here : Why this step? Total arithmetic is independent of hardware — it's a property of the math.
Step 2 — Output tiles. Output is . The array produces a output block per residency. Tiles . Why this step? When the matrix exceeds the grid, we loop the grid over sub-blocks (tiling). Each tile is one full array residency.
Step 3 — MACs per tile. Each output block () sums over : . Times 4 tiles . ✓ matches Step 1. Why this step? Cross-check that tiling doesn't change the total work — it only splits it in time.
Recall Verify
, equal to . Tiling conserves work. ✓
Example 4 — Cell D: pipeline fill and drain on a small layer
Recall Forecast
If it takes ~256 cycles to fill and another ~256 to drain, but only 16 rows of real data flow, is the array mostly working or mostly starting/stopping? ::: Mostly overhead — fill + drain dwarf the 16.
Step 1 — Fill latency. Data must traverse the array width: 256 cycles before the first full result emerges. Why this step? From the fill definition: the wavefront needs (array-width) hops to reach the far edge.
Step 2 — Streaming the real data. Once filled, each of the rows costs 1 more cycle: 16 cycles of useful streaming. Why this step? After the pipe is full, throughput is 1 row/cycle — this is the only "at full speed" phase.
Step 3 — Drain latency. After the last row is injected, its partial sums must still walk out the far edge: 256 cycles of drain. Why this step? The drain definition: the tail of the wave must exit before the last answer is complete. Ignoring it undercounts the true latency.
Step 4 — Total cycles and overhead fraction. Why this step? This is the honest "small layer" penalty: 97% of cycles are fill+drain, not full-throughput work.
Recall Verify
. Sanity: a big layer () gives overhead — negligible. Fill+drain hurt only small layers. ✓
Example 5 — Cell E: degenerate input (, and )
Recall Forecast
With , each output is just one multiply (no accumulation). Does the array's depth (the accumulation direction) help? ::: No — depth collapses to 1, so that whole dimension is wasted.
Step 1 — Total MACs. : Why this step? Even a degenerate layer still touches every output once.
Step 2 — Total cycles = fill + compute + drain. There is only row of activation to inject, so useful streaming is 1 cycle. Around it sit the fill and drain of a 256-wide grid: Why this step? Without writing the cycle count explicitly the utilisation number below would appear from nowhere. Here the "1 compute cycle" is the only productive tick; everything else is startup/shutdown of the pipe.
Step 3 — Utilisation over the run. The grid could do MACs each cycle; over 513 cycles its capacity is . Actual useful MACs : Why this step? The degenerate case exposes the worst utilisation — fill+drain swamp the single compute cycle.
Recall Verify
. The truly degenerate () needs 1 MAC on 65536 PEs → over its 513-cycle run, . Tiny inputs waste the array — exactly why NPUs suit large matmuls. ✓
Example 6 — Cell F: memory-bound limit (roofline)
Recall Forecast
If only 4 ops happen per byte and 100 billion bytes arrive per second, the math ceiling from bandwidth is ::: ops/s = 0.4 TOPS — far below 131 TOPS, so memory-bound.
Step 1 — Bandwidth-limited compute. Let be the most operations per second the bandwidth can sustain — the throughput ceiling set purely by how fast bytes arrive: Why this step? Throughput can't exceed (bytes/s that arrive) × (ops done per byte). This is the slanted memory roof of the Roofline model. Units: . ✓
Step 2 — Convert that ceiling to the topline metric, TOPS. Why this step? Every other example reported speed in TOPS; to compare against the TOPS compute roof we must put the memory ceiling in the same unit.
Step 3 — Classify: compute-bound or memory-bound? Compute ceiling = TOPS; memory ceiling = TOPS. Since , the achievable throughput is the lower of the two → memory-bound, capped at TOPS. Why this step? The roofline always picks the lower roof; here bandwidth, not the PEs, is the bottleneck.
Step 4 — Effective utilisation of the array. Why this step? Shows peak TOPS is a fiction when data is starved — the "peak TOPS tells you the speed" trap made concrete.

Recall Verify
ops/s TOPS; . Ridge: to become compute-bound you need , i.e. ops/byte. Below that, add bandwidth or reuse, not PEs. ✓
Example 7 — Cell G: precision trade (int8 vs fp32)
Step 1 — Area ratio. Why this step? fp32 uses 32 bits, int8 uses 8; apply the square rule just defined.
Step 2 — New PE count. fp32 grid: PEs. int8 fits : PEs → a grid. Why this step? Same area ÷ 16× smaller multiplier = 16× the count; so each side quadruples ().
Step 3 — Peak TOPS at 1 GHz. Why this step? Confirms the throughput multiplier for the same silicon and clock.
Recall Verify
. Accuracy caveat: int8 inference typically loses <1% accuracy with calibration — the trade is worth it (see Quantization and int8 inference and Tensor cores, which mix precisions). ✓
Example 8 — Cell H: real-world word problem
Recall Forecast
The chip's MAC budget per second vs the model's demand — which is bigger? ::: The chip has huge headroom; demand needs only a slice.
Step 1 — Chip MAC budget per second. Why this step? Convert hardware to a "MACs I can do per second" ceiling (note: MACs, not ops — no ×2 here).
Step 2 — Model demand per second. Why this step? Frame rate turns per-frame work into a sustained rate we can compare.
Step 3 — Fits? → yes, with large margin.
Step 4 — Required utilisation. Why this step? Tells us the chip is idle 99%+ of the time → we can lower clock/voltage to save battery (Energy per operation).
Recall Verify
; . Battery insight: since only 0.69% is needed, drop ~150× → same 30 fps at far lower power. ✓
Example 9 — Cell I: exam twist (solve for the unknown)
Recall Forecast
Rearranging for needs a square root. Roughly, is near 100, 200, or 500? ::: Around 200.
Step 1 — Write the TOPS formula with . Why this step? "Square array" means , so PE count is ; we now have one unknown.
Step 2 — Solve for . Why this step? Isolate the count first — cleaner than square-rooting mid-expression.
Step 3 — Take the root. Why this step? must be a side length, so we square-root the PE count.
Recall Verify
Forward-check: TOPS. ✓
The matrix, filled
Recall Did every cell get covered?
A→Ex1, B→Ex2, C→Ex3, D→Ex4, E→Ex5, F→Ex6, G→Ex7, H→Ex8, I→Ex9 ::: all nine cells covered, from full array to degenerate , memory-bound, precision, real-world, and reverse-solve.