6.1.4 · D2Parallelism & Multicore

Visual walkthrough — Multicore vs manycore designs

2,698 words12 min readBack to topic

This page builds the central result of multicore vs manycore from absolute zero: the equation that decides whether you want a few fast cores or many slow cores. That equation is Amdahl's Law. We will not assume you have ever seen it. We will draw it into existence, one bar at a time.


Step 1 — Draw the work as a bar of time

WHAT. Forget cores for a moment. Take one program and let it run on one core. Measure how long it takes. Call that total time — the length of the whole bar.

WHY. Speedup is always a comparison: new time versus old time. So we need a baseline first. Everything later is measured against this one bar.

PICTURE. The full bar below is . We have not split anything yet — this is the "before" picture.

Figure — Multicore vs manycore designs

Step 2 — Split the bar into two honest pieces

WHAT. Colour the bar in two parts. One part is code that can run in parallel (many workers at once). The other part is code that must run one step at a time — no splitting allowed.

WHY. Not all code is equal. Adding a list of a million numbers? Split it — that is parallel. But "read the config file, THEN start the engine, THEN load the level" — each step needs the previous one done first. That is serial. The whole story hinges on this one split.

PICTURE. The red slice is the serial part — the part that will refuse to shrink no matter how many cores you buy. The black slice is parallel.

Figure — Multicore vs manycore designs

Step 3 — Turn the pieces into fractions (make it size-free)

WHAT. Instead of measuring in seconds, measure each piece as a fraction of the whole bar. Let be the parallel fraction. Then the serial fraction is whatever is left: .

WHY. Seconds depend on the machine, the input, the weather. A fraction does not. Saying "90% of this program is parallel" () is a fact about the program itself, true on any hardware. This is why we divide out the units — the law should be about the code, not the clock.

PICTURE. Same bar, now labelled at the left and at the right. The red serial slice has width ; the black parallel slice has width .

Figure — Multicore vs manycore designs

Step 4 — Hand the parallel slice to cores

WHAT. Now the machinery. We finally name the number of cores. Let ==== be how many cores we give the program. Give it cores (see thread-level parallelism for how those cores get fed). The parallel slice gets shared across all — so it shrinks to of its old length. The serial slice does not shrink at all: one worker, one step at a time.

WHY. This is the whole point of parallel hardware: split the splittable work. If cores each take a quarter of the parallel work, that piece finishes in a quarter of the time — and here is where the idealized "perfect load-balancing" assumption earns its keep: we assume each core gets an exactly equal quarter. But the serial piece has nobody to hand work to — it is stuck at full length.

PICTURE. Watch the black parallel slice collapse to while the red serial slice stays exactly the same width. The red bar is the villain of the whole story — stare at it.

Figure — Multicore vs manycore designs

Step 5 — Speedup gets a name: = old bar ÷ new bar

WHAT. We now define the quantity we have been chasing and give it a symbol. Let ==== stand for speeduphow many times shorter the new bar is. Divide the old length by the new length.

WHY. "Twice as fast" literally means "half the time", i.e. old÷new . That is exactly the ratio we compute. Naming it lets us write it once and reason about it cleanly. It is a definition, not a trick.

PICTURE. Old bar (length ) sits on top of the shrunken new bar (length ). The speedup is how many new bars fit into the old one.

Figure — Multicore vs manycore designs

Step 6 — Push to infinity: the wall appears

WHAT. Ask the extreme question: what if we had infinitely many cores? Let . Then .

WHY. This is the single most important sentence in the whole topic. It tells us the best case ever, the ceiling no amount of hardware can beat. If the ceiling is low, buying more cores is pointless — and that is when manycore loses.

PICTURE. As grows, the parallel slice vanishes to a hair, but the red serial slice stays put. The bar cannot get shorter than the red block. That red block is the wall.

Figure — Multicore vs manycore designs

Step 7 — The speedup curve flattens (the picture that decides the war)

WHAT. Plot speedup on the vertical axis against number of cores on the horizontal axis, for a few values of .

WHY. A curve shows what a single number hides: diminishing returns. Early cores help a lot; later cores barely move the line. The shape is the argument.

PICTURE. Each curve rises then flattens into a horizontal ceiling at height (the red dashed line for ). High- workloads (matrix math, SIMD-friendly, near the top) keep climbing — those go to manycore GPUs. Low- workloads flatten early — those stay on multicore.

Figure — Multicore vs manycore designs

Step 8 — The degenerate corners (never leave a case unshown)

WHAT. Check the three extreme inputs so the formula never surprises you. Crucially, we do not invent new formulas for these — each corner is just a value of or plugged into the same from Step 5.

WHY. A law you cannot sanity-check at its edges is a law you do not trust. Every corner must give an answer that feels right — and every one must fall out of the general expression, not a special rule.

PICTURE. Three mini-bars: fully serial (no shrink), fully parallel (shrinks to almost nothing), and single core (no change).

Figure — Multicore vs manycore designs
Case Inputs Plug into Meaning
Fully serial No parallel part → cores do nothing. Speedup .
Fully parallel Perfect scaling → cores give . The GPU dream.
Single core One core = the baseline. Speedup by definition. ✓

Notice all three answers came out of the one general formula — the extremes and are legal inputs, not exceptions.


The one-picture summary

Everything above — the bar, the split, the shrink, the ceiling — in a single frame.

Figure — Multicore vs manycore designs
Recall Feynman retelling — say it back in plain words

A program is a bar of time. Colour it: the red part must run one-step-at-a-time, the black part can be split. Give it cores — only the black part shrinks, to of its size (assuming, ideally, perfect equal splitting and zero overhead); the red part refuses to budge. We measure everything relative to the original bar (), so speedup is just the old bar (=1) divided by the new, shrunken bar, which gives . Now imagine more and more cores: becomes negligibly small, the black part disappears entirely, but the red part is still there — so the best you can ever do is , set purely by how much red there is. Plot it and every curve flattens into that ceiling. If your code is mostly red (serial, branchy), the curve flattens instantly, so buy a few very fast cores — that's multicore. If your code is almost all black (, like matrix math), the curve climbs forever, so buy thousands of tiny cores — that's manycore. The whole multicore-vs-manycore choice is just: how much red is in your bar?

Recall Quick self-test

With and , what is ? ::: With , what is the ceiling as ? ::: Why does the red (serial) block never shrink? ::: Only one worker can run it, one step at a time — there is nothing to split, so never appears in the term. Which curve shape screams "build a manycore GPU"? ::: One that keeps climbing (near ), so every added core still earns real speedup. Name one assumption that makes real speedup worse than the formula. ::: Any of: imperfect load-balancing, thread-startup overhead, or communication/coherence cost — all assumed to be zero here.