Parallel Decomposition

Gustafson's Law

The complement to Amdahl, not the refutation. Amdahl fixes the problem and asks how much faster a bigger machine makes it. Gustafson fixes the time budget and asks how much bigger a problem the machine lets you solve — and for that question the scaling looks almost linear.

▶ Run the lab

The question this answers

The question

If bigger machines barely help a fixed job, why does everyone keep buying them?

The work

A nightly risk simulation with a hard one-hour window. On one core it runs 40,000 Monte Carlo paths in that hour; the question is not how fast 40,000 paths get on 32 cores, but how many paths fit in the same hour.

What is shared

Nothing across simulation paths — each is independent. The serial part is the fixed setup and the final aggregation, and the crucial observation is that its *absolute* time does not grow when the problem does.

The invariant — what must stay true under every interleaving

The serial section takes the same absolute time regardless of problem size or worker count, so as the parallel work grows to fill the machine, the serial fraction of the run shrinks and the achievable throughput grows nearly linearly with workers.

Synchronization exists to preserve this sentence. If a schedule can make it false, the code is wrong no matter which primitive it uses.

WorkCan it overlap?Can it parallelise?What is shared?What ordering?What synchronization?Where is contention?What can deadlock?What can race?What is gained?What complexity?

The other question, and why the answer looks so different

Amdahl asks: given this exact job, how much faster does it run on P workers? That is strong scaling, and the answer is bounded by 1/s. Gustafson asks: given P workers and a fixed time budget, how much work can I get done? That is weak scaling, and the answer is roughly linear in P. Neither is wrong. They are answers to different questions, and which one applies to you is a property of the workload, not of the mathematics.

The reason the answers differ so much is a single modelling assumption. Amdahl holds problem size constant, so as workers increase the parallel time shrinks toward zero while the serial time stays fixed — the serial part comes to dominate. Gustafson holds *run time* constant and grows the problem to fill the machine, so the parallel work grows with P while the serial time stays fixed — the serial part becomes a shrinking fraction. Same fixed serial cost, two opposite consequences, purely because of what is held constant.

The worked example below is the practical form. In the one-hour window on one core, the job spends 3 minutes on setup and aggregation and 57 minutes simulating. On 32 cores, the same 3 minutes of serial work remains, and the 57 minutes of parallel budget now runs 32 paths at once — about 1.28 million paths instead of 40,000. Nobody made anything 30× faster; the machine did about 30× more work in the same hour, which for this workload is exactly what was wanted.

  • Strong scaling: fixed problem, more workers, how much faster? Bounded by 1/s.
  • Weak scaling: fixed time, more workers, how much more work? Roughly linear in P.
  • The formula, second: scaled speedup ≈ s + P(1 − s), where s is the serial fraction *of the parallel run*.
  • The assumption that does the work: the serial section's absolute cost does not grow with problem size.
BUDGET: 60 minutes, every night, non-negotiable.

ONE CORE
  setup + load market data            2.0 min   serial
  simulate paths                     57.0 min   parallel  -> 40,000 paths
  aggregate + write report            1.0 min   serial
                                     --------
                                       60.0 min   40,000 paths

THIRTY-TWO CORES, SAME HOUR
  setup + load market data            2.0 min   serial     <- unchanged
  simulate paths                     57.0 min   parallel   <- now 32-wide
                                                           -> 1,280,000 paths
  aggregate + write report            1.0 min   serial     <- unchanged
                                     --------
                                       60.0 min   1,280,000 paths

  scaled speedup = work done / work done on one core
                 = 1,280,000 / 40,000  =  32x            <- nearly linear

WHAT AMDAHL WOULD SAY ABOUT THE *ORIGINAL* JOB
  serial fraction s = 3/60 = 0.05,  ceiling = 20x
  40,000 paths on 32 cores: 2.0 + 57/32 + 1.0 = 4.78 min  -> speedup 12.6x

BOTH ARE TRUE AND THEY ANSWER DIFFERENT QUESTIONS:
  Amdahl     "how fast is TONIGHT'S job on the new machine?"      12.6x
  Gustafson  "how much better a simulation fits in the hour?"     32x  (~30x paths)

WHICH ONE IS YOURS depends on whether more work is worth anything.
  More paths -> tighter confidence intervals -> yes, worth something.
  A batch that must simply finish -> extra capacity buys nothing -> Amdahl.
One hour of wall clock, one core versus thirty-two. Arithmetic on a model, not a measurement.

The scaled-speedup curve, and where it stops being linear

Under Gustafson's assumptions the curve is a straight line with slope (1 − s), which is why weak scaling is the shape supercomputing centres quote and strong scaling is the shape application teams get disappointed by. The curve below shows it at 5% serial: 30.45× at 32 workers, 121.65× at 128 — no ceiling in sight, because there is no ceiling in the model.

The honest part is naming where the model stops holding, and there are three places. The serial part does not always stay fixed. Aggregating 1.28 million path results takes longer than aggregating 40,000, so if the combine grows with problem size it is not serial-fixed and the linearity degrades. The parallel part does not always scale perfectly. Memory bandwidth, cache pressure and coordination cost all grow with worker count, so the effective per-worker throughput falls (Parallel Overhead, Memory Bandwidth: More Cores, Same Bus). And a bigger problem may not be worth anything. Ten times the paths is genuinely better; ten times a report nobody reads is not.

That third point is not a mathematical caveat but the actual decision. Gustafson applies when marginal work has marginal value: more simulation paths, finer grid resolution, more training data, larger batches, more candidate plans. It does not apply when the job is "process today's transactions" — that problem has a fixed size set by the world, and no machine makes there be more of them. For those workloads Amdahl is the only relevant law and the ceiling is real.

Scaled (weak) speedup at 5% serial: work completed in a fixed time budget. Computed from Gustafson's formula — a model, not a measurement.ILLUSTRATIVE
1 workerdashed = linear speedup128 workers · max 128.0×
The curve tracks just below ideal with a constant slope of (1 − s), because the fixed serial time is a shrinking share of a growing job. It departs from reality wherever the model's assumptions fail: if the aggregation step grows with problem size it is not serial-fixed and the line bends; if memory bandwidth or coordination cost limits per-worker throughput the slope falls; and if the extra work has no value the speedup is real but worthless. Nothing here is measured.

Deciding which law is yours

The question to ask is: if I had twice the machine, would I run the same job faster, or a bigger job? If the answer is "the same job faster", you are in Amdahl's world and the serial fraction is your ceiling. If the answer is "a bigger job", you are in Gustafson's world and near-linear scaling is available — provided the extra work is genuinely useful and the serial part really is size-independent.

Most real systems are a mixture and the two laws apply to different parts. A nightly pipeline may have a fixed-size ingestion stage (Amdahl: the ceiling is real) feeding a model-training stage where more data is better (Gustafson: buy cores). Treating the whole pipeline with one law produces either misplaced pessimism or unjustified hardware.

And there is a third pattern neither law describes that is often the right answer for services: scaling *throughput* across independent requests. Ten cores serving ten concurrent users is near-linear regardless of either law, because each user's job has its own serial section that overlaps another user's parallel section. If your goal is requests per second rather than latency per request, the serial fraction of a single request stops being the binding constraint entirely — which is why service capacity planning looks nothing like batch-job scaling (Choosing a Concurrency Model for a Server).

WorkloadProblem sizeLaw that appliesWhat more cores buyWatch out for
Nightly batch that must finish by 06:00Fixed by the worldAmdahlA faster finish, up to the 1/s ceilingBuying past the knee of the curve
Monte Carlo / simulation with a time budgetChosen by youGustafsonMore paths, tighter confidenceAn aggregation step that grows with path count
Model training with a fixed windowChosen by youGustafsonMore data, more epochs, bigger modelCommunication cost growing with workers
Compiling one large programFixedAmdahlFaster builds, capped by link and dependency orderThe link step and the dependency critical path
Rendering a fixed frame at fixed resolutionFixedAmdahlLower latency, cappedFixed setup per frame
Rendering at whatever quality fits 16 msChosen by youGustafsonHigher quality at the same frame ratePer-frame serial work becoming the budget
A web service under loadMany independent requestsNeither — throughput scalingMore concurrent requests, near-linearlyShared resources that serialise across requests
Which law describes your workload, and what it implies about spending money.

Key points

  • Gustafson is the complement to Amdahl, not a refutation: different question, different quantity held constant.
  • Amdahl fixes the problem and asks how much faster (strong scaling, bounded by 1/s); Gustafson fixes the time and asks how much more work (weak scaling, roughly linear).
  • The load-bearing assumption is that the serial section's absolute cost does not grow with problem size.
  • Scaled speedup ≈ s + P(1 − s), a straight line with slope (1 − s) and no ceiling in the model.
  • It applies only when more work has value — more simulation paths yes, more copies of an unread report no.
  • Ask: with twice the machine, would I run the same job faster or a bigger job? That answer selects the law.
  • Service throughput across independent requests is a third pattern neither law describes, and it scales better than both.

The loop, answered

Every field is required, which is why no lesson here can recommend concurrency without naming the interleaving that breaks it, the complexity it adds, and the simpler thing to consider first.

How it works
  • Fix a time budget rather than a problem size.
  • Observe that the serial portion of the run takes a fixed absolute time, independent of how much parallel work is added.
  • Scale the parallel work up until it fills P workers for the remainder of the budget.
  • The work completed is therefore s + P(1 − s) times what one worker completes in the same budget.
  • The serial fraction *of the run* shrinks as the problem grows, which is why the curve does not bend.
  • Validate the assumptions empirically: check that serial time really is flat as the problem grows, and that per-worker throughput really holds up as P grows.
Interleavings that matter
  • At 32 workers each simulating a distinct path set, no interleaving affects the result — the paths share nothing, which is what makes the problem weak-scalable in the first place.
  • The serial setup runs once while 31 workers wait; because the parallel phase is now much longer, that wait is a smaller share of the run than it was on one core.
  • The aggregation step folds 32× more results; if it is linear in result count it is no longer size-independent, the model's assumption breaks, and the line bends.
  • All 32 workers stream distinct data through a shared memory subsystem: per-worker throughput drops even though nothing is logically shared, and the achieved slope falls below (1 − s).
  • A worker finishes its path set early and idles until the budget ends — weak scaling still requires balance, and the same straggler logic as Fork/Join applies.
What it guarantees — and does not
  • Guaranteed: if the serial time is genuinely size-independent and the parallel part scales, work completed grows nearly linearly with workers.
  • NOT guaranteed: that a bigger problem is a better one. The law measures work, not value.
  • NOT guaranteed: that the serial part stays fixed. Aggregation, I/O and output frequently grow with problem size.
  • NOT guaranteed: perfect parallel scaling. Bandwidth, communication and coordination costs grow with P and flatten the slope.
  • NOT guaranteed: that it applies to your workload at all. Fixed-size problems are Amdahl's, and no reframing changes that.
  • NOT guaranteed: that weak scaling implies strong scaling. A system can weak-scale to 1,000 workers and still be limited to 12× on a fixed problem.
Where contention appears
  • Contention grows with worker count regardless of which law you are applying, so the slope of the weak-scaling line is reduced by exactly the effects Amdahl's curve exposes more visibly.
  • A larger problem may exceed cache capacity, so per-worker efficiency falls even with no logical sharing (Parallelism Can Destroy Locality).
  • Aggregation across more workers is more synchronization at the end of the run, and it grows with P.
  • In distributed weak scaling, communication frequently grows faster than compute, which is the usual reason real weak-scaling curves bend well before the model does.
How it fails
  • Applying weak-scaling logic to a fixed-size problem and buying hardware that delivers Amdahl's ceiling instead of Gustafson's line.
  • A serial section that quietly grows with problem size, so the curve bends and the "linear scaling" claim stops holding.
  • Scaling up work that has no marginal value — real speedup, no benefit.
  • Per-worker throughput decay from bandwidth or communication, misread as a problem-size effect.
  • Load imbalance at large P leaving workers idle inside the fixed budget.
  • Quoting weak-scaling numbers as if they answered a strong-scaling question, which is the most common way benchmark claims mislead.
When it helps
  • Simulation, Monte Carlo, numerical solvers and anything where more samples or finer resolution genuinely improves the result.
  • Model training and hyperparameter search, where extra capacity converts directly into more exploration.
  • Rendering and analysis with a quality knob and a fixed time budget.
  • Capacity conversations: it is the correct argument for buying more machine when the problem can grow, and the correct rebuttal to a blanket "Amdahl says no".
When it hurts
  • Fixed-size jobs, where it produces optimistic projections that the workload cannot deliver.
  • When the serial or aggregation step grows with problem size and the assumption is not checked.
  • When it justifies growing a problem for its own sake — more resolution than anyone can use is cost without benefit.
  • When quoted as a scaling result without saying which quantity was held constant, which makes the number uninterpretable.
How you would know
  • Weak-scaling test: grow the problem proportionally with workers and check that wall time stays flat. A rising line is the assumption failing.
  • Strong-scaling test alongside it: fixed problem, growing workers. You need both to describe a system honestly.
  • Serial-phase wall time as a function of problem size — the direct check on Gustafson's core assumption.
  • Work completed per unit time per worker, which should be flat under weak scaling and falls when bandwidth or communication bites.
  • Value of the extra work, measured in whatever the domain cares about: confidence interval width, model accuracy, image quality. Speedup with no value delta is not a result.
  • Idle worker time within the fixed budget, which quantifies imbalance at large P.
Complexity it introduces
  • The problem size becomes a tunable parameter coupled to the machine, so results are no longer comparable across runs unless the size is recorded.
  • Reporting requires stating which quantity was held constant, or the number is meaningless — this is a documentation obligation, not a nicety.
  • Growing the problem often changes memory footprint qualitatively, pushing working sets out of cache or a node's memory.
  • Aggregation logic must be checked for size-independence, and made so if it is not — usually by making it a tree reduce rather than a linear fold.
Simpler alternatives
  • Amdahl's analysis, when the problem size is fixed by the world — the honest framing for most batch and request-path work.
  • Throughput scaling across independent jobs, when the goal is aggregate work rather than either latency or problem size.
  • A better algorithm, which improves both fixed-size and scaled cases and composes with parallelism.
  • Reducing the required quality or sample count, when the current problem size was chosen arbitrarily and a smaller one is sufficient.

Why is 8 cores only 4.5×?

Why is 8 cores only 4.5×?
Amdahl is one term of four. Turn each effect off and watch which part of the curve straightens.
1 workerdashed = linear speedup16 workers · max 16.0×
workersidealAmdahl onlyrealisticlimited by
11.0×1.00×1.00×none
22.0×1.90×1.85×serial
44.0×3.48×3.19×serial
66.0×4.80×4.17×serial
88.0×5.93×4.17×bandwidth
1010.0×6.90×4.17×bandwidth
1212.0×7.74×4.17×bandwidth
1414.0×8.48×4.17×bandwidth
1616.0×9.14×4.17×bandwidth
speedup at 8 workers
4.17×
best point on the curve
4.17× @ 6
past best, adding workers
costs
distinct causes on curve
serial, bandwidth
At 8 workers this configuration reaches 4.17× and the dominant cause is "bandwidth". Past 6 workers the cores are fed by a memory system that is already saturated — they are stalled, not computing. More threads make the stall queue longer. The fix is fewer bytes per unit of work (better locality, smaller types), not more parallelism. The reason to name the cause is that each one has a different fix, and three of the four get worse if you respond by adding threads.
SIMULATEDcomposed from named effects, not fitted to a measurement

Amdahl's law: the serial ceiling

Amdahl's law — the serial fraction sets a ceiling
Speedup = 1 / (s + (1 − s)/n). The serial part does not get faster, so it decides the answer long before the core count does.
1 workerdashed = linear speedup32 workers · max 32.0×
speedup at 32
7.80×
ceiling at ∞ workers
10.0×
efficiency
24.4%
workers doing nothing
24.2 of 32
s = 0.10   n = 32
Amdahl    S(n) = 1 / (s + (1 − s)/n) = 7.805×        ← fixed problem, more machine
                 S(1 000 000)        = 10.000×     ← a million cores, and still under 10×
Gustafson S(n) = s + n(1 − s)        = 28.900×        ← fixed time, bigger problem
10.0% serial caps you at 10.0×, forever. At 32 workers you get 7.80× — 24.4% efficiency, with 24.2 workers' worth of capacity paid for and idle. A million cores would only reach 10.00×. The lever is not the core count; it is the 10.0%. Shrink the serial region (a smaller critical section, a lock-free counter, a per-worker accumulator merged once) and the whole curve moves. Buy hardware and nothing moves.
fixed problem, growing machineSIMULATED

CPU parallelism simulator

Scaling 100 CPU tasks
100 independent tasks of 20 ms each. The tasks do not share anything — the job around them does.
SIMULATEDA composed model, not a benchmark.

Amdahl’s term, a synchronisation term, an oversubscription term and a bandwidth ceiling, each one a knob you can switch off. Real curves have more causes than four and are rarely this smooth. There is no ideal core count to read off this chart.

Cores
The serial part is the split and the merge, not the tasks. The sync term is what each worker pays to coordinate with the others. The ceiling is where the memory system stops feeding cores, whatever the core count says.
1 workerdashed = linear speedup16 workers · max 16.0×
ideal
4.0× · 500 ms
Amdahl only
3.48×
modelled
3.28× · 610 ms
efficiency
82%
Where the 4× went
delivered3.3×
lost to the serial part0.5×
lost to sync, switching and bandwidth0.2×
At 4 cores the model delivers 3.28× of a possible 4×, so 109 ms of the run is overhead rather than work. The serial part dominates. Splitting the input, merging the results and the one section that cannot overlap now cost more than the cores save — and no core count fixes that term.
One hundred tasks that share nothing still do not scale linearly, because the job that owns them is not the tasks. Read the gap between the dashed line and the curve as the price of coordination — and note it is charged even when every task is independent.
limited by: serialSIMULATED

What people believe, and what is true

Claim

Gustafson disproves Amdahl.

Reality

They hold different quantities constant and answer different questions. Both are correct simultaneously for the same system.

Claim

Our system scales linearly to 128 workers.

Reality

That is a weak-scaling claim unless the problem size was fixed. The same system may be capped at 12× on a fixed problem, and both numbers describe it accurately.

Claim

If we buy more cores, we can just run a bigger problem and get linear scaling.

Reality

Only if the bigger problem is worth something and the serial and aggregation steps do not grow with it. Check both before the purchase.

Claim

Weak scaling means the serial fraction stopped mattering.

Reality

The serial time is unchanged; it is a smaller share of a longer run. Shorten the budget or shrink the problem and it dominates again immediately.

Go deeper

Overview

A bigger machine may not finish today's job much faster, but it lets you do a much bigger job in the same time. Whether that is useful depends on whether a bigger job is worth anything.

Practical

Ask whether extra capacity would run the same job faster or a bigger job. Then quote the matching law, and always state which quantity you held constant.

Advanced

Verify the assumption: measure serial-phase time as the problem grows. Aggregation that scales with result count silently converts a weak-scaling system into a bending curve.

Internals

Scaled speedup s + P(1 − s) has no ceiling because the parallel work is defined to grow with P. Every real bend comes from an assumption failing — growing serial work, communication cost, or bandwidth saturation.

Apply it