How it works
The explanation, with examples you can run.
Pipelines
Executing one instruction takes several steps, and each needs different hardware. A pipeline lets them overlap: while instruction 1 executes, instruction 2 is being decoded and instruction 3 fetched, like cars on an assembly line. Modern cores go further. They are superscalar (several pipelines, so several instructions can start per cycle) and out of order: instructions wait in a buffer until their inputs are ready and then run, even if earlier instructions are still waiting for memory. Results are committed in program order, so the program can't tell, apart from the speed.
The enemy of a pipeline is not knowing what comes next. A load that misses the cache can take hundreds of cycles (the next topic), and a dependent instruction must wait for it. A branch is worse: until the condition is computed, the CPU doesn't know which instructions to fetch.
Branch prediction
Rather than wait, the CPU guesses. A branch predictor remembers how each branch behaved recently and predicts the same pattern again; the core then runs speculatively down the predicted path. A correct guess costs nothing. A wrong one means discarding the speculative work and restarting, typically 15 to 20 cycles on current desktop cores.
Press Run to see what your code prints, in order.
Runs in this browser, in an isolated frame with no access to this page. console.log, info, warn and error are shown; code runs as a classic script, so use an async function for await.
On a Mac laptop with Node 22, the random array took about 30 ms per pass and the sorted one about 6 ms, the same work on the same numbers. With random values the if is a coin toss and the predictor is wrong about half the time. Sorted, it sees one long run of "skip" followed by one long run of "add". Your numbers will differ, and a compiler may remove the branch altogether (with a conditional move), in which case the gap disappears.
What this means day to day
- Predictable code is fast code. Data-dependent branches inside hot loops are expensive when the data is random; sorting, partitioning or branch-free arithmetic can help.
- Clock speed isn't everything. Performance is roughly clock rate × instructions per cycle (IPC). Profilers such as
perf statreport IPC and branch-miss counts, which tell you whether the CPU is busy or waiting. - Speculation leaks. Spectre-class vulnerabilities (2018) showed that speculative execution leaves traces in the caches that attackers can measure. Operating systems, browsers and language runtimes now include mitigations that cost some performance.
Most of the time a core is not limited by arithmetic at all but by waiting for memory, which is the next topic.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.