Amdahl's Law and Speedup

Imagine you speed up 90% of a program by a factor of 100, but leave the remaining 10% untouched. A naive guess says the program runs nearly 100 times faster. The truth is closer to 9 times faster. This holds no matter how extreme the improvement to that 90%. This gap between intuition and reality is exactly what Amdahl's Law formalizes. It is one of the most consequential inequalities in computer architecture. The law matters because hardware designers constantly face a choice. They can spend transistor budget, power budget, or engineering effort making one part of a system much faster. Or they can spread improvements more evenly. Multicore chips, GPUs, vector units, and specialized accelerators all make some fraction of a workload faster. The rest — serial control logic, memory stalls, I/O, synchronization — keeps running at the old speed. Amdahl's Law tells you, precisely and quantitatively, how much that fraction limits your payoff. It does this before you spend a single dollar building the accelerator. The big picture is a single sobering fact: the unaccelerated part of a computation becomes the bottleneck, and it does so quickly. As you push the speedup of the accelerated part toward infinity, total speedup does not diverge. Instead, it converges to a hard ceiling. That ceiling is set entirely by the fraction of work you couldn't speed up. This is why architects obsess over reducing serial fractions. They do this via better parallel algorithms, pipelining, and reducing synchronization overhead. This matters more than simply throwing more parallel hardware at a fixed serial core. This article builds Amdahl's Law from the CPU time equation. It derives the classic formula and its asymptotic limit. It walks through multiple worked numerical traces, including a multicore scaling scenario. It also shows where the law governs real engineering decisions. These range from deciding core counts on a die to justifying whether an accelerator is worth building at all.

Key takeaways
  • Amdahl's Law bounds the overall speedup achievable when only a fraction of a program can be sped up.
  • Speedup formula: S(f,s)=1(1−f)+f/sS(f, s) = \dfrac{1}{(1-f) + f/s}, where ff is the parallelizable/accelerable fraction and ss is its local speedup.
  • As s→∞s \to \infty, speedup converges to a hard ceiling: 11−f\dfrac{1}{1-f} — determined solely by the serial fraction.
  • Small serial fractions dominate at scale: even 5% serial code caps speedup at 20×, however many processors you add.
  • The law is a bound derived from arithmetic on execution time, not an empirical claim — it is provably tight.
  • It motivates reducing serial/synchronization overhead as much as building faster parallel hardware, foreshadowing multicore design and Gustafson's Law and Scaling.
The core insight

Overall speedup is capped by the fraction of the program you cannot accelerate, no matter how fast you make the rest.

The idea

Amdahl's Law, named for computer architect Gene Amdahl, quantifies the speedup obtainable when an improvement applies to only part of a task. Define the enhanced fraction ff as the fraction of the original execution time spent in the portion of the program that can be sped up (by parallelizing it, vectorizing it, or offloading it to specialized hardware). Define the local speedup ss as the factor by which that portion alone is sped up when run in isolation. The overall speedup SS is the ratio of old total execution time to new total execution time. This builds directly on the Performance Metrics and the CPU Time Equation: execution time is a sum of components, and speeding up one component changes only that component's contribution to the sum. Amdahl's Law is nothing more than careful bookkeeping of that sum — its power comes from making an intuitive idea mathematically inescapable. The key terminological distinction to keep straight: ff is measured as a fraction of the original (unenhanced) execution time, not a fraction of code, not a fraction of instructions, and not a fraction of the enhanced execution time. Confusing these is the single most common source of misapplied Amdahl's Law calculations. The law generalizes beyond parallel processors. It applies to any situation where you accelerate a part of a system: a faster floating-point unit that only helps floating-point-heavy code, a cache that only helps memory-bound sections, an FPGA accelerator that only handles one kernel of a pipeline. In every case, the fraction of time not covered by the enhancement becomes an unmovable floor under total execution time, and that floor is what sets the ceiling on speedup.

How it works

Start from total execution time normalized to 11 (i.e., treat the original execution time as one unit of time). Split it into the fraction that can be enhanced, ff, and the fraction that cannot, 1−f1-f:

Told=(1−f)+f=1T_{\text{old}} = (1 - f) + f = 1

Applying a local speedup of ss to the enhanced portion shrinks only that portion's contribution to time:

Tnew=(1−f)+fsT_{\text{new}} = (1 - f) + \frac{f}{s}

The unenhanced part (1−f)(1-f) is untouched — it still takes the same amount of time it always did. Overall speedup is old time over new time:

S(f,s)=ToldTnew=1(1−f)+fsS(f, s) = \frac{T_{\text{old}}}{T_{\text{new}}} = \frac{1}{(1 - f) + \dfrac{f}{s}}

This is Amdahl's Law. Two special cases are worth internalizing immediately. If f=1f = 1 (the entire program is enhanced), S=sS = s: you get the full local speedup, as expected. If f=0f = 0 (nothing is enhanced), S=1S = 1: no improvement at all, also as expected. The interesting behavior lives in between, and especially in the limit:

lim⁡s→∞S(f,s)=11−f\lim_{s \to \infty} S(f, s) = \frac{1}{1 - f}

This limit is the asymptotic speedup ceiling. It says that even an infinitely fast enhancement to a fraction ff of the program can never produce more than 11−f\frac{1}{1-f} times speedup overall. If 90%90\% of a program is parallelized (f=0.9f = 0.9), the ceiling is 10.1=10×\frac{1}{0.1} = 10\times — regardless of how many processors you add. This is the mathematical explanation for the "9× not 100×" observation in the overview.

The algorithm / procedure

Applying Amdahl's Law in practice is a small, precise procedure — typically done at design time to evaluate whether a proposed hardware or software enhancement is worthwhile. ``` function AmdahlSpeedup(f, s):

# f: fraction of ORIGINAL execution time affected by the enhancement, 0 <= f <= 1

# s: local speedup of the affected fraction when run alone, s >= 1 require 0 <= f <= 1 require s >= 1 unaffected_time = 1 - f affected_time_new = f / s T_new = unaffected_time + affected_time_new S = 1 / T_new return S function AmdahlCeiling(f):

# Speedup as local speedup s -> infinity require 0 <= f < 1 # f == 1 has no finite formula needed: ceiling is unbounded return 1 / (1 - f) function RequiredLocalSpeedup(f, S_target):

# Solve S(f, s) = S_target for s, given the target must be achievable require 0 < f <= 1 max_possible = AmdahlCeiling(f) if f < 1 else infinity if S_target >= max_possible: return "unreachable: target exceeds ceiling 1/(1-f)"

# Invert: S = 1 / ((1-f) + f/s) => (1-f) + f/s = 1/S => f/s = 1/S - (1-f) denom = (1.0 / S_target) - (1 - f) s = f / denom return s function MulticoreSpeedup(f, n):

# Special case: enhancement = distributing the parallel fraction over n identical cores

# local speedup s = n, assuming perfect load balancing and no overhead return AmdahlSpeedup(f, n) ``` Each function is a direct algebraic manipulation of the core formula — there is no search, no iteration, no approximation. Correctness reduces entirely to correctness of the derivation above. The one subtlety worth flagging in code: `RequiredLocalSpeedup` must check the target against the asymptotic ceiling before dividing, because as Starget→11−fS_{\text{target}} \to \frac{1}{1-f} from below, s→∞s \to \infty, and beyond it the denominator `denom` becomes zero or negative — an unreachable target, not a numerical glitch.

Figure
Amdahl's Law: execution time before and after enhancing a fraction f of the program
Time budget before vs. after enhancement Before (T_old = 1) serial (1−f) parallel/enhanceable f divide enhanced part by speedup s After (T_new = (1−f) + f/s) serial (1−f) f/s as s→∞, f/s→0: floor = (1−f)

Complexity & correctness

Computational complexity. Evaluating Amdahl's Law is O(1)O(1) time and O(1)O(1) space — it is a closed-form arithmetic expression with a constant number of operations (one subtraction, one division, one addition, one more division). There is no algorithmic complexity to analyze in the traditional sense; the "complexity" content of this topic is about the asymptotic behavior of the formula itself as s→∞s \to \infty, which is a limit, not a runtime cost.

Correctness argument. The derivation is exact, not approximate, under its stated assumptions, so correctness is a matter of checking the bookkeeping: 1. Partition invariant. Total original time is partitioned into exactly two disjoint pieces, enhanceable and non-enhanceable, that sum to the whole: (1−f)+f=1(1-f) + f = 1. This holds by definition of ff as a fraction of total time — no double-counting, no gaps. 2. Enhancement invariant. The enhancement changes only the enhanceable piece, and changes it by exactly a multiplicative factor ss: the new time for that piece is f/sf/s because ss is defined as local speedup (old-piece-time / new-piece-time restricted to that piece). The unenhanced piece is provably unaffected because the enhancement, by construction, does not touch it. 3. Monotonicity. Tnew(s)=(1−f)+f/sT_{\text{new}}(s) = (1-f) + f/s is strictly decreasing in ss for fixed f>0f>0, so S(f,s)=1/Tnew(s)S(f,s) = 1/T_{\text{new}}(s) is strictly increasing in ss — more local speedup never hurts, confirming the formula behaves sensibly. 4. Limit. Since f/s→0f/s \to 0 as s→∞s \to \infty (for fixed finite ff), Tnew→(1−f)T_{\text{new}} \to (1-f), hence S→1/(1−f)S \to 1/(1-f). This is a rigorous limit of a rational function, not a heuristic approximation — the ceiling is exact, not a rule of thumb. 5. Tightness. The ceiling 1/(1−f)1/(1-f) is attained only in the limit and is never exceeded for any finite ss, because f/s>0f/s > 0 strictly whenever ss is finite and f>0f>0, making Tnew>(1−f)T_{\text{new}} > (1-f) strictly, hence S<1/(1−f)S < 1/(1-f) strictly. So the bound is both correct and the best possible bound of its form.

Honest tradeoffs and assumptions. Amdahl's Law as stated assumes: (a) the problem size is fixed — the same fixed workload is executed before and after, (b) the serial fraction (1−f)(1-f) is truly fixed and does not shrink or grow with ss or with the number of processors, and (c) there is no overhead from the act of parallelizing itself (communication, synchronization, load imbalance). Assumption (a) is precisely what Gustafson's Law and Scaling challenges — it asks what happens if problem size grows with available parallelism instead of staying fixed, which yields a much less pessimistic picture for scaling. Assumption (c) is optimistic in practice: real synchronization and communication costs can make the effective serial fraction larger than the code's algebraic serial fraction, making real speedups worse than Amdahl's Law predicts, never better. This is why the law is best understood as an upper bound on achievable speedup, not a guaranteed target.

Worked example

Scenario 1 — the sobering ceiling. A video encoder spends 95% of its time in a routine that can be perfectly parallelized across cores (f=0.95f = 0.95), and 5% in an inherently serial setup/teardown routine (1−f=0.051-f = 0.05).

Cores used (≈ local speedup ss)Tnew=(1−f)+f/sT_{\text{new}} = (1-f) + f/sSpeedup SS
10.05+0.95=1.000.05 + 0.95 = 1.001.00×1.00\times
20.05+0.475=0.5250.05 + 0.475 = 0.5251.90×1.90\times
40.05+0.2375=0.28750.05 + 0.2375 = 0.28753.48×3.48\times
80.05+0.11875=0.168750.05 + 0.11875 = 0.168755.93×5.93\times
160.05+0.059375=0.1093750.05 + 0.059375 = 0.1093759.14×9.14\times
640.05+0.01484=0.064840.05 + 0.01484 = 0.0648415.42×15.42\times
10240.05+0.000928=0.0509280.05 + 0.000928 = 0.05092819.64×19.64\times
∞\infty (ceiling)0.050.0520.00×\mathbf{20.00\times}

Notice the diminishing returns: quadrupling cores from 16 to 64 buys only about 1.7×1.7\times more speedup, and going from 64 to 1024 cores (a 16× increase in hardware) buys barely 1.27×1.27\times more. The ceiling 1/(1−0.95)=20×1/(1-0.95) = 20\times is approached but never reached.

Scenario 2 — comparing two engineering choices. Suppose you can either (A) parallelize an additional part of the code, raising ff from 0.950.95 to 0.990.99 while keeping s=16s = 16, or (B) keep f=0.95f = 0.95 but double core count so s=32s = 32. Which helps more?

  • Option A: S=1(1−0.99)+0.99/16=10.01+0.061875=10.071875≈13.91×S = \dfrac{1}{(1-0.99) + 0.99/16} = \dfrac{1}{0.01 + 0.061875} = \dfrac{1}{0.071875} \approx 13.91\times
  • Option B: S=1(1−0.95)+0.95/32=10.05+0.0296875=10.0796875≈12.55×S = \dfrac{1}{(1-0.95) + 0.95/32} = \dfrac{1}{0.05 + 0.0296875} = \dfrac{1}{0.0796875} \approx 12.55\times

Option A wins, despite not increasing core count at all — because it attacks the serial fraction directly. This is the practical lesson architects draw from the law: reducing the serial fraction is usually worth more than adding raw parallel throughput, since the serial fraction is what caps the ceiling.

Scenario 3 — required speedup to hit a target. A team wants 5×5\times overall speedup and knows f=0.8f = 0.8 (80% of the workload is parallelizable). What local speedup ss do they need? Ceiling check first: 1/(1−0.8)=5.01/(1-0.8) = 5.0. The target S=5S=5 equals the ceiling, which per the tightness argument above is unreachable at any finite ss — the team would need s→∞s \to \infty. This is a critical, easy-to-miss failure mode: naive algebra gives s=f/(1/S−(1−f))=0.8/(0.2−0.2)=0.8/0=∞s = f / (1/S - (1-f)) = 0.8 / (0.2 - 0.2) = 0.8/0 = \infty, correctly signaling impossibility rather than producing a bogus finite answer.

Common pitfalls & traps

PitfallWhy it happensFix
Measuring ff as a fraction of code lines instead of execution timeConfusing static code structure with dynamic time spentAlways measure ff via profiling: time spent in the enhanceable region divided by total original time
Using ff relative to the new (enhanced) execution time instead of the originalRecomputing the fraction after the speedup changes the denominatorFix ff once, from the original, unenhanced run; never recompute it post-hoc
Assuming speedup scales linearly with number of processorsIgnoring the serial fraction entirelyAlways run the number through the formula — verify against the asymptotic ceiling 1/(1−f)1/(1-f)
Treating ss as core count without accounting for overheadAssuming zero synchronization/communication costTreat nn cores as giving at most s=ns=n; real s<ns < n due to contention, so treat the Amdahl number as an upper bound
Trying to solve for ss when the target speedup meets or exceeds the ceilingNaive algebra doesn't flag the singularityCheck Starget<1/(1−f)S_{\text{target}} < 1/(1-f) before inverting the formula
Forgetting f=1f=1 and f=0f=0 sanity checks when validating a derivationSkipping boundary-case verificationAlways check S(1,s)=sS(1,s)=s and S(0,s)=1S(0,s)=1 hold in any formula you derive

Pioneers & history

Gene Amdahl was a computer architect best known as chief architect of the IBM System/360 mainframe family, one of the most influential computer architectures in history for introducing a unified instruction set across an entire product line of varying performance and cost. In 1967, while arguing against overly optimistic claims being made for massively parallel computer designs at the AFIPS Spring Joint Computer Conference, Amdahl presented the argument that a fixed serial fraction of any program imposes a hard limit on the speedup obtainable from parallel processing. The observation, delivered as a short conference paper rather than a formal theorem, has since become one of the most cited results in computer architecture — a rare case of a single-page argument reshaping decades of hardware design philosophy.

Origins · 1 minGene Myron Amdahl and how this was discovered
GM
Gene Myron Amdahl
1922–2015 · IBM System/360 chief architect; formulated the speedup–serial-fraction tradeoff in 1967

History
- 1922 — Gene Amdahl born in Flandreau, South Dakota.
- 1952 — Amdahl completes his PhD at the University of Wisconsin–Madison, designing the WISC computer.
- 1965 — Amdahl serves as chief architect of the IBM System/360 mainframe family.
- 1967 — Amdahl presents "Validity of the Single Processor Approach to Achieving Large Scale Computing Capabilities," introducing the serial-fraction speedup limit.
- 1988 — John Gustafson publishes a rebuttal-style reframing (scaled speedup) addressing Amdahl's fixed-problem-size assumption, motivating Gustafson's Law and Scaling.

Where this matters

Amdahl's Law directly governs core-count and design decisions in every modern multicore and manycore processor, from smartphone SoCs to datacenter server chips discussed under Multicore Processors and Thread-Level Parallelism. Chip architects use it to decide how much silicon area to devote to additional cores versus improving single-thread performance (larger caches, better branch prediction, wider pipelines), because beyond a certain point, adding cores yields vanishing returns if the software's serial fraction hasn't shrunk. GPU and accelerator design (for machine learning training chips, cryptographic accelerators, video codecs) is justified using exactly this arithmetic: an accelerator that speeds up 99% of a workload by 1000× is far more valuable than one that speeds up 100% of it by 10×, and Amdahl's Law makes that comparison precise before any silicon is fabricated. Software engineers apply the same reasoning to distributed systems and multi-threaded applications: reducing lock contention, minimizing serialization points, and eliminating single-threaded bottleneck stages in a pipeline are all direct attacks on the serial fraction (1−f)(1-f), and the law explains why those efforts often matter more than adding worker threads. Database query planners, MapReduce/Spark job schedulers, and compiler auto-parallelization passes all implicitly reason in Amdahl's terms when deciding whether parallelizing a given code region is worth the overhead. Even outside computing, the same mathematics — a fixed bottleneck stage capping a system built from partly-improvable components — recurs in manufacturing throughput analysis and queueing-theoretic bottleneck analysis, making Amdahl's Law a template for "constrained-resource" reasoning across engineering disciplines.

Ask the tutor: How does adding realistic synchronization overhead change the Amdahl's Law formula, and how much does it typically shrink real-world speedups compared to the ideal prediction?

What exactly does "fraction f" mean in Amdahl's Law?

ff is the proportion of the original, unenhanced program's execution time that is spent in the part of the program you plan to speed up — for example, by parallelizing it across cores or offloading it to an accelerator. It is measured empirically, typically by profiling a single run of the unmodified program and timing how long the relevant section takes relative to total runtime. It is not a count of source lines, not a count of instructions, and critically not recomputed from the sped-up program's runtime — doing so is one of the most common sources of error when applying the law.

Why does the speedup formula have a hard ceiling instead of growing without bound?

The ceiling exists because the unenhanced portion of the program, (1−f)(1-f), is completely unaffected by the enhancement — it takes exactly as long after the enhancement as before. As you increase the local speedup ss of the enhanced part toward infinity, that part's contribution to total time shrinks toward zero, but the fixed (1−f)(1-f) term never shrinks. Total time is bounded below by (1−f)(1-f), so speedup — old time divided by new time — is bounded above by 1/(1−f)1/(1-f). This is a direct algebraic consequence, not an empirical trend.

Is Amdahl's Law pessimistic or unrealistic for modern parallel computing?

It is realistic under its stated assumption: a fixed problem size run on varying amounts of parallel hardware. Under that assumption it is exact and provably tight, not merely a rough estimate. It becomes overly pessimistic only when problem size is allowed to grow with available parallelism — many real workloads (bigger simulations, larger datasets) scale this way, which is exactly the regime Gustafson's Law addresses. Both laws are correct; they simply model different real-world scenarios, and knowing which one applies to your workload is the important engineering judgment.

How is Amdahl's Law used in real hardware design decisions?

Chip designers use it to decide the marginal value of adding more parallel execution units, cores, or accelerator throughput to a design, given a profiled serial fraction from representative workloads. If profiling shows a workload is 70% parallelizable, the team knows the absolute ceiling is about 3.3×, so investment beyond a certain core count yields negligible returns and is better redirected toward single-thread performance, larger caches, or reducing the serial fraction itself (better algorithms, less locking, pipelined I/O). This calculation is done before committing to silicon area, since fabrication costs make wrong bets extremely expensive.

Can Amdahl's Law be applied to something other than multicore processors?

Yes — it applies to any partial enhancement of a system with additive time components. Examples include speeding up floating-point instructions with a faster FPU (helps only floating-point-heavy code), adding a cache (helps only memory-bound sections), or building an FPGA/GPU accelerator for one kernel of a larger pipeline. In every case you identify the fraction of original time attributable to the part being enhanced and the local speedup of that part, then apply the same formula. This generality is why the law appears throughout performance engineering, not just in parallel processor design.

What is the difference between "local speedup" and "overall speedup"?

Local speedup ss is how much faster the enhanced portion runs, measured in isolation — for instance, a routine that ran in 10 seconds now running in 1 second has local speedup s=10s=10. Overall speedup SS is how much faster the entire program runs, accounting for the fact that only part of the program benefited. Amdahl's Law is precisely the function that converts a local speedup into the overall speedup you actually experience, and the gap between the two grows dramatically as ff moves away from 1.

Does synchronization or communication overhead appear anywhere in the basic Amdahl's Law formula?

No — the basic formula assumes the enhancement introduces zero additional overhead, so it represents a best-case, idealized upper bound. Real parallel systems incur costs from thread synchronization, cache coherence traffic, communication latency, and load imbalance, all of which effectively enlarge the serial fraction beyond what static code analysis would suggest. Extended forms of the model add explicit overhead terms to TnewT_{\text{new}}, but the standard formula taught as "Amdahl's Law" is the overhead-free version, and real speedups are typically somewhat below what it predicts.

Before this

Where this leads