Visual walkthrough — Vector - SIMD instructions (SSE, AVX, NEON)
This page rebuilds the parent note's central result — how much faster does SIMD make your loop? — from absolute zero. We will earn every symbol before using it, and every step gets a blueprint figure you can point at.
If you have not yet seen the big idea, read the parent topic first. The one sentence you need to carry in: one instruction chews on several numbers at once. Everything below turns that sentence into a formula.
Step 1 — Count the work the slow way (scalar)
WHAT. A scalar loop touches numbers one at a time. Imagine an array of numbers laid in a row. The machine walks the row, handling exactly one box per step.
WHY. Before we can say "SIMD is faster," we need a fair baseline: the honest cost of doing it one-at-a-time. You cannot measure "faster" without a "slower" to compare against.
PICTURE. Below, each amber box is one array element. The white arrow visits one box at a time. Count the arrow-visits — that is our workload.

Let us name things carefully:
- ::: how many numbers are in the array (here ; always ). It is just a count — no units.
- ::: how many CPU cycles one element costs — this is the shared from the ground rules. One box = ticks.
Multiply "number of boxes" by "ticks per box":
is the total time (in cycles) for the scalar loop. That is our baseline.
Step 2 — Pack numbers into a wide register
WHAT. A vector register is a single storage slot wide enough to hold several numbers side by side. We call each side-by-side slot a lane. The number of lanes is the vector width .
WHY. This is the whole trick of SIMD. Instead of one number per hand, the CPU grabs numbers in one fist. We must define now because the speedup is going to be built entirely out of it.
PICTURE. One long cyan register split into lanes, each holding one number. One load instruction fills all four lanes at once.

- ::: vector width — how many numbers fit in one register at once. This depends on the hardware, not your data.
Concrete values from the parent note, so is not abstract:
| Instruction set | Register width | Numbers () for 32-bit floats |
|---|---|---|
| SSE (128-bit) | 128 bits | |
| AVX (256-bit) | 256 bits | |
| AVX-512 (512-bit) | 512 bits |
This ties straight to data parallelism: the same operation, many independent data items, no talking between lanes.
Step 3 — Count the work the fast way (SIMD)
WHAT. One SIMD instruction processes a whole register — all lanes — in the same cycles a scalar op took (that was our ground-rule assumption ). So instead of single steps, we take groups of .
WHY. This is where the saving appears. If each instruction still costs cycles but now clears boxes instead of , we need far fewer instructions.
PICTURE. The same 8 boxes, but now bracketed into two groups of four. Each bracket is one instruction.

How many groups do we need? Divide the boxes by lanes: . In the picture groups. So a first guess is:
But might not be a whole number — you cannot run "half an instruction." We fix that next.
Step 4 — The ceiling: partial groups still cost a full instruction
WHAT. The symbol (ceiling) means "round up to the next whole number." So , but and .
WHY. A register instruction fires on the whole register even if only one lane holds real data. Ten elements with need instructions: one full group of 8, plus a second instruction for the leftover 2 (the other 6 lanes are wasted but still "along for the ride").
PICTURE. Ten boxes, . Group 1 and Group 2 are full; Group 3 is only half-full but still costs one whole instruction (its empty lanes shaded amber = wasted).

So the honest SIMD time is:
- ::: the number of vector instructions actually issued, never a fraction.
Step 5 — Form the speedup ratio
WHAT. Speedup is defined as "old time divided by new time." If the new way takes half the time, (twice as fast).
WHY. A ratio is the natural way to say "how many times faster." It cancels the unit "cycles," leaving a pure multiplier you can quote as "."
PICTURE. Two horizontal time-bars drawn to scale: the long scalar bar over the short SIMD bar. is literally "how many short bars fit inside the long one."

Notice the on top and bottom are the same — this is precisely our ground rule : one element costs the same whether it rides alone or in a lane. So they cancel:
- The disappearance of is the key insight: speedup does not depend on how expensive the operation is — only on how many elements share a lane. (This cancellation is only legal because , which holds since means real work exists.)
Step 6 — The large-array limit: why S → w
WHAT. When is much bigger than (written ), the ceiling barely matters — one wasted partial group is a rounding blip on thousands of full groups. So .
WHY. This gives the clean headline number people quote. We drop the ceiling because for big data it changes the answer by less than one instruction out of many.
PICTURE. A curve: plotted against for . It sawtooths near the origin (ceiling effects) then flattens toward the dashed amber line .

WHAT IT MEANS. The best you can hope for is a speedup equal to the number of lanes: on SSE, on AVX, on AVX-512. This is the ideal that Loop Vectorization and Auto-vectorization chase.
Step 7 — Edge and degenerate cases
WHAT. The formula is exact and covers every input with . Let us walk the corners so nothing surprises you.
WHY. The parent note quotes "–" as the ideal but "–" in reality. The gap lives entirely in these edge cases. A reader who only saw would be shocked by real benchmarks; we defuse that now.
PICTURE. Four mini-panels, one per case, each showing the box layout and its .

- Case (empty array). Ruled out by our ground rule — no work, no speedup, is undefined. Nothing to draw.
- Case (exactly one full register). . Full speed, no waste.
- Case (fewer elements than lanes, e.g. ). . You still issue one instruction but only lanes carry real data — speedup is , not . Tiny arrays cannot reach the ideal.
- Case (a single element). . No speedup at all — SIMD degenerates to scalar, and the setup overhead can make it slower.
- Case "not divisible" (e.g. ). , below the ideal because of the wasted lanes in the second instruction (the remainder problem from the parent note).
The reasons real speedup lands at – instead of — memory bandwidth, unaligned loads, scalar tails — are the practical ceiling on top of this arithmetic ceiling. Memory bandwidth in particular ties into Cache Optimization: if the data cannot arrive fast enough, extra lanes sit idle.
The one-picture summary
WHAT. One blueprint compressing the entire chain: the scalar row of boxes, the grouping into registers, the two time-bars, and the ratio that survives after cancels — ending at .
WHY. So the whole argument lives in your head as a single image, not seven scattered ones. When you later recall "why is SIMD times faster?", this picture should replay: same work, fewer presses, time-per-press cancels, only lane-count remains. That is the payload of the entire page in one glance.

Recall Feynman retelling
Picture a row of chocolates you have to wrap. Wrapping them one by one takes as many moves as there are chocolates — that's , where is the time for one wrap. (And you need at least one chocolate, — wrapping an empty row is not "faster," it is just nothing.)
Now you get a magic tray that wraps chocolates in a single press — and crucially, one press takes the same time as wrapping one chocolate by hand, because the tray works all its slots at once. You load at a time, so you only press the button times — rounding up because even a half-full tray needs a whole press. That's .
"How many times faster?" is just the old time over the new time. The time-per-press appears in both, so it cancels — meaning it does not matter whether wrapping is quick or slow, only how many fit on the tray. You are left with .
If you have loads of chocolates, the odd leftover tray barely matters and the answer settles at exactly the tray size, : an 8-lane tray is 8× faster. But with just one chocolate, the tray gives you nothing (), and with a leftover handful the wasted tray slots drag you below the ideal. That gap — plus real-world snags like data arriving too slowly — is why the shiny "8×" becomes a solid "5×" in practice.
Recall Quick self-check
Why does cancel in the speedup? ::: Because we assumed a vector instruction costs the same cycles as a scalar one (); the ratio keeps only the count of elements vs. instructions, so divides out. For , , what is ? ::: . Why is the ideal speedup exactly ? ::: Because with , , and . What happens when ? ::: — no speedup; SIMD collapses to scalar. Why must ? ::: For both times are and is undefined — you cannot speed up doing no work.