Figure s01 — Left: 8 jobs = 2 full waves. Right: 9 jobs = 3 waves, the last one mostly idle. The ceiling is the maths word for "one leftover forces a whole extra wave."
Cell check.Why?9/4=2.25 is not whole → Cell C, the leftover job forces an extra wave.
Waves.Why?⌈9/4⌉=⌈2.25⌉=3. Waves 1 and 2 are full (4+4=8 jobs), wave 3 holds the last 1 job.
Time.Why?Tparallel=2×3=6 min.
Idle slots.Why? In wave 3, 4−1=3 runners do nothing. So S=18/6=3, which is less than m=4 — the ceiling penalty.
Figure s02 draws all three waves as rows of lavender boxes. Rows 1 and 2 are full (four jobs each); row 3 shows one lavender job beside three grey "idle" boxes. Read the row labels down the left: each wave adds 2 minutes, so the stack totals 2×3=6 min, printed in coral at the bottom.
Figure s02 — 9 jobs on 4 runners: the third wave carries a single job while 3 runners idle, dragging speedup down to 3 (below m=4).
Case D, cell check.Why?m=1 means only one job runs at a time — parallelism is switched off.
Case D, waves.Why?⌈5/1⌉=5 waves. Tparallel=4×5=20 min =Tserial. Parallel formula collapses into the serial formula — good, they must agree at m=1.
Case E, cell check.Why?n=0: there is nothing to run. ⌈0/4⌉=⌈0⌉=0 waves.
Case E, time.Why?T=t×0=0 min. An empty stage is instant (in this idealised model — real engines have tiny overhead, but the formula says 0).
Recall Why we always test the degenerate inputs
A formula you trust must survive its boundaries. m=1must reduce to serial; n=0must give 0. If a formula misbehaves at the edges, it is wrong in the middle too. This is the same discipline as checking θ at the quadrant boundaries.
Per-run time before.Why? Without cache each run pays d+r=90+200=290 s.
Per-run time after.Why? A cache hit swaps d for c: c+r=6+200=206 s. Note r is untouched — caching only attacks the install part.
Saving per run.Why?d−c=90−6=84 s. This is the whole payoff of caching, per run.
Daily saving in seconds.Why? Multiply the per-run saving by the number of runs: k(d−c)=40×84=3360 s.
Convert seconds to minutes.Why this step? We were asked for the answer in minutes, but every input above was in seconds, so the raw total 3360 is in seconds. To change units we divide by 60 (there are 60 seconds in a minute): 3360/60=56 min/day. Skipping this step would report "3360" as if it were minutes — a 60× error.
Test time.Why?⌈6/3⌉=2 waves → 3×2=6 min. (Test is not just 3 min — the 6 shards need 2 waves.)
Deploy time.Why? One job → 2 min.
Sum the stages.Why? Sequential stages add: 4+6+2=12 min.
Figure s03 lays the pipeline out left-to-right: a mint Build box, an arrow into a 2×3 grid of butter Test boxes (the two waves of three), an arrow into a coral Deploy box. The arrows are the DAG dependencies that force order; the caption sums the stage times to 12 minutes.
Figure s03 — Stages chained by arrows add their times (4 + 6 + 2 = 12 min); the Test stage itself is two parallel waves of three jobs.
Translate to symbols.Why? Word problems fail when you skip this. "240 tests, 5 s each, one after another" → ntests=240, ttest=5 s, run serially. "10 equal shards on 10 runners" → generic n=10 shards, m=10 runners, each shard running 240/10=24 tests.
Before (laptop, serial).Why? All 240 tests one after another: ntests×ttest=240×5=1200 s =1200/60=20 min (÷60 to convert seconds to minutes, since the ask is in minutes).
Per-shard time.Why? Each shard runs 24 tests: generic t=24×ttest=24×5=120 s.
After (10 shards, 10 runners).Why?⌈n/m⌉=⌈10/10⌉=1 wave, all shards at once → T=t×1=120 s =2 min.
Build the table.Why? We want to see the cap, not just assert it.
m
waves ⌈8/m⌉
T=3×waves
S=24/T
1
8
24
1
2
4
12
2
4
2
6
4
8
1
3
8
16
1
3
8
Read the cap.Why? From m=8 to m=16, T stays at 3 min and S stays at 8. Speedup flattens the moment m≥n.
Explain it.Why? You cannot split 8 independent jobs across more than 8 machines at once — the 9th machine has nothing to do. So S≤nalways.
Figure s04 plots S (lavender line, coral dots) against m. The curve climbs 1,2,4,8 then goes flat as a table-top at 8; a mint dashed line marks the ceiling S=n=8, and a coral arrow labels the flat part "extra runners useless."
Figure s04 — Speedup rises with runners but flattens hard at S = n = 8: past m = 8 the extra machines add nothing.
Simulate the greedy schedule.Why? With unequal times the answer depends on placement. Sort jobs descending: 7,3,3,1.
t=0: Runner A takes 7, Runner B takes 3.
t=3: B is free, takes the next 3 (finishes at 6).
t=6: B free, takes 1 (finishes at 7).
A finishes its 7 at t=7.
Read the finish.Why? The pipeline is done when the last runner finishes: max(7,7)=7 min.
Naive formula for contrast.Why? Using average t=(7+3+3+1)/4=3.5 min and ⌈4/2⌉=2 waves gives 3.5×2=7 min — here it happens to match, but only by luck of these numbers.
Break the coincidence.Why this step? One matching case does not prove the naive formula safe — we must show a case where it fails. Change the jobs to {9,1,1,1} (same n=4, same m=2). Greedy: A takes the 9 (finishes at 9); B mops up 1+1+1=3 (finishes at 3). True finish =max(9,3)=9 min. But the naive formula uses average t=(9+1+1+1)/4=3 min and ⌈4/2⌉=2 waves, giving 3×2=6 min. So naive says 6 while reality is 9 — the naive formula under-estimates by 3 minutes. The single "elephant" job (the 9) sets the floor; averaging hides it.
Ex1 :::> A (m≥n)
Ex2 :::> B (divides evenly)
Ex3 :::> C (ceiling bites)
Ex4 :::> D & E (m=1, n=0)
Ex5 :::> F (caching)
Ex6 :::> G (mixed serial + parallel)
Ex7 :::> H (word problem)
Ex8 :::> I (speedup cap)
Ex9 :::> J (unequal job times)
See also: the parent topic, and for the theory of the cap, Amdahl's Law. The sharding idea sits on top of Automated Testing — Unit vs Integration vs E2E, runs on Docker & Containerization runners, and expresses the DevOps Principles & Shift-Left philosophy.