CPUcpufront endexecution unitsblock diagrammicroarchitecture

What Is Actually Inside a CPU

A CPU is not one thing that runs instructions. It is a front end that fetches and decodes them, a set of execution units that do the work, a register file they read and write, and caches feeding all of it — with most of the silicon spent on keeping those units busy rather than on the arithmetic itself.

Follow the mechanism

Software view, hardware view

The gap between what you wrote and what the machine does is where this whole domain lives.

The question
What are the actual parts of a CPU, and which of them does my code interact with?
What you wrote
A processor executes my instructions, one after another, at some number of gigahertz.
What the hardware does
A pipeline of specialised structures: a front end that fetches bytes and turns them into operations, a scheduler that issues those operations to whichever execution unit is free, a register file they read and write, and a cache hierarchy that exists because memory is far away.
Almost every performance surprise in this domain comes from a part of the CPU that has no representation in source code. You cannot reason about a stall, a misprediction or a cache miss without a mental model that has more than one box in it.
SourceCompilerInstructionsFront EndExecutionRegistersCachesMemoryI/OBehavior

The blocks, and what each one is for

SIMPLIFIEDA four-region model. Real cores add micro-operation caches, multiple decode paths, load/store queues, fill buffers, multiple schedulers and reorder machinery — all omitted here and introduced later in [[out-of-order-execution]] and [[reorder-buffer]].

A useful first model of a core has four regions. The front end turns bytes in memory into operations the machine can schedule: it fetches from the instruction cache, decodes, and predicts where control flow goes next. The back end executes: a scheduler picks operations whose inputs are ready and issues them to execution units — integer ALUs, load/store units, vector units, and usually more than one of each. The register file is the working storage those units read and write. The cache hierarchy sits behind everything, because main memory is far enough away that a core would otherwise spend most of its life waiting.

What is worth noticing is the proportion. The arithmetic — the part that corresponds to a + b in source — is a small fraction of the machine. Most of the transistor budget goes to *keeping the arithmetic fed*: caches, prediction, buffering, scheduling. That proportion is the entire reason this domain exists. If arithmetic were the bottleneck, performance work would be about counting operations. It usually is not, so it usually is not.

The split between front end and back end is the first diagnostic distinction to learn. A core can be starved at the front (it cannot supply operations fast enough — instruction cache misses, mispredictions, decode limits) or stalled at the back (it has operations but cannot complete them — waiting for data, waiting for a busy unit, waiting on a dependency). These are different problems with different fixes, and Busy Is Not the Same as Working is where that split gets turned into a measurement.

bytes → operationswhen inputs readyon hiton missInstruction cacheFetch + branch predictionDecodeSchedulerInteger ALUsLoad / store unitsVector unitsData cacheL2 / L3 / memoryRegister file
UserLLMAgentToolDataDecisionHumanGuardrail

Front end starved, or back end stalled?

Because the two halves fail differently, the same symptom — "the CPU is busy but slow" — has two completely different explanations, and the counters distinguish them cleanly. A front-end problem means the machine cannot get operations to the scheduler: the code footprint is too large for the instruction cache, or branches are unpredictable enough that the fetcher keeps being redirected. A back-end problem means operations are queued and cannot retire: they are waiting for a load, for a divider, or for each other.

This is not an academic split. The fixes are disjoint. Front-end pressure is addressed by making code smaller and more predictable — less inlining, fewer branches on unpredictable data, hot paths kept together (Your Code Is Data Too, Branch Prediction: Guessing Well Enough to Matter). Back-end pressure is addressed by making data closer or dependency chains shorter (Memory Moves in Lines, Not Variables, Dependency Graphs: The Real Shape of Your Code). Applying the wrong one is how a week disappears with nothing to show.

A learner should leave this lesson able to ask, of any slow loop: is the machine failing to *supply* work, or failing to *finish* it? That question is answerable with counters and unanswerable by reading source code, which is the recurring shape of this whole domain.

The same "busy but slow" symptom, two different machines underneath
Front end starvedBack end stalled
What is happeningScheduler is empty; nothing to issueScheduler is full; nothing can complete
Typical causesInstruction cache misses, branch mispredictions, decode bottlenecksData cache misses, long dependency chains, contended units like the divider
Counter signatureHigh front-end stall cycles; high branch-miss or I-cache-miss rateHigh back-end stall cycles; high data cache or memory counters
What helpsSmaller hot code, more predictable branches, better layoutBetter data locality, shorter dependency chains, more parallel work
What does notOptimising arithmetic that was never the constraintShrinking code that was already fitting comfortably
Read nextYour Code Is Data Too, Misprediction: What a Wrong Guess CostsThe Memory Hierarchy, Instruction-Level Parallelism

What this picture deliberately leaves out

Every block diagram of a CPU is a lie of omission, and it is worth naming the omissions rather than discovering them later as contradictions. The model above shows one of each unit; real cores have several integer ALUs and can issue multiple operations per cycle (Superscalar Execution). It shows instructions flowing in order; real cores execute them as inputs become available and only *retire* them in order (Out-of-Order Execution, The Reorder Buffer and Precise State). It shows a register file with the registers the ISA defines; real cores have many more physical registers and rename onto them (Register Renaming).

It also omits everything about how bytes become operations on a variable-length ISA, where a single instruction may decode into several internal operations, and where a cache of already-decoded operations can bypass the decoders entirely. That machinery is real and it is microarchitectural — meaning it differs between vendors, between generations from the same vendor, and sometimes between cores on the same die.

The reason to state this explicitly is that these diagrams are how misconceptions get installed. A learner who believes the picture is the machine will later conclude that a modern CPU executes one instruction at a time, in order, and that its speed is its clock rate. All three are wrong, and ISA vs Microarchitecture: The Distinction Everything Depends On and The Clock: Why GHz Is Not Performance exist to unpick exactly those.

  • Omitted: width. Real cores fetch, decode, issue and retire several operations per cycle.
  • Omitted: order. Execution is out of order; only retirement is in order.
  • Omitted: renaming. The registers the ISA names are not the registers the machine uses.
  • Omitted: the memory pipeline. Load/store queues, fill buffers and prefetchers sit between the load unit and the cache.
  • Omitted: everything heterogeneous. Many current CPUs mix core types with different capabilities on one die.
What the four-region model omits, and where each omission is covered
OmittedRealityCovered in
WidthSeveral operations fetched, issued and retired per cycleSuperscalar Execution
OrderingExecution follows operand readiness; only retirement is in orderOut-of-Order Execution
RenamingArchitectural register names are mapped onto a larger physical fileRegister Renaming
Memory pipelineLoad/store queues, fill buffers and prefetchers sit before the cachePrefetching: The Hardware Guesses What You Will Read Next
HeterogeneityMany current CPUs mix core types with different capabilities on one dieCore, Hardware Thread, Software Thread

Key points

  • A CPU is a front end that supplies operations and a back end that executes them; most silicon exists to keep the arithmetic fed rather than to perform it.
  • Front-end starvation and back-end stalling produce the same "busy but slow" symptom and have disjoint fixes.
  • The register file, execution units and caches are the parts your code actually interacts with, mostly without saying so.
  • Every CPU block diagram omits width, out-of-order execution and renaming — treat it as a teaching device, not a description.
  • The question worth carrying forward: is the machine failing to supply work, or failing to finish it?

Follow the mechanism

The path through the machine, hop by hop — and the conclusions it invites that are wrong.

  1. 1
    Program counter → instruction cache: the front end requests the bytes at the current address.
  2. 2
    Instruction cache → decode: raw bytes are turned into internal operations the scheduler understands.
  3. 3
    Decode → scheduler: operations wait here until their input operands are available.
  4. 4
    Scheduler → execution unit: an operation whose inputs are ready is issued to a free ALU, load/store unit or vector unit.
  5. 5
    Execution unit → register file → retirement: the result is written back and the instruction becomes architecturally visible in program order.
What people conclude from this — wrongly
  • "The CPU is at 100%, so it is compute-bound." Utilisation counts cycles in which the core was not idle, including cycles spent entirely stalled on memory.
  • "Fewer instructions means faster." Only if the machine was limited by instruction supply; if it was waiting for data, the shorter instruction stream waits just as long.
  • "The diagram shows one ALU, so one operation happens at a time." Width and out-of-order issue are precisely what the simplified picture omits.

Consequences, controls and cost

What it causes
  • • Code with a large hot footprint can be slow for reasons entirely unrelated to the arithmetic it performs.
  • • Two programs executing the same number of instructions can differ in runtime by an order of magnitude depending on whether the back end ever stalls.
  • • Adding more arithmetic can be free when the machine is waiting on memory, which is why micro-optimising an inner expression often changes nothing.
What you can do
  • • Measure which half is the constraint before optimising either — front-end and back-end stall counters answer this directly ([[performance-counters]]).
  • • Keep hot code small and hot data close; these address the two halves respectively.
  • • Expose independent work so the scheduler has something to issue while one chain waits ([[instruction-level-parallelism]]).
  • • Accept that most of this is not directly controllable, and that measuring it is the skill rather than steering it.
How to see it
  • • Read front-end versus back-end stall cycles from the performance counters your platform exposes; the split is the first useful measurement on any hot loop.
  • • Compare instructions retired against cycles elapsed to get IPC, then interpret it with [[cpi]] rather than in isolation.
  • • Profile to find the hot region first — a whole-program counter reading averages over code that does not matter ([[cpu-profiling]]).
What it costs
  • • The four-region model is simple enough to reason with and wrong in every detail that matters for peak performance work.
  • • Counter-based diagnosis requires platform-specific tooling and privileges that are often unavailable inside containers and cloud VMs.
  • • Reasoning at this level is only worth it once profiling has established that a specific loop matters; applied everywhere it is a waste of engineering time.

Scope

§224 — what these claims are specific to.

What these claims are specific to
  • SIMPLIFIEDA four-region teaching model. Real cores add micro-op caches, multiple schedulers, load/store queues and retirement machinery not shown here.
  • MICROARCH-SPECIFICUnit counts, issue width, buffer sizes and decode behaviour differ between vendors, between generations from one vendor, and between core types on the same heterogeneous die.

Misconceptions

Claim
“A CPU executes one instruction at a time.”
Reality
A modern core has many instructions in flight simultaneously, executes them as their inputs become ready rather than in program order, and completes several per cycle when dependencies allow. Program order is preserved only at retirement, which is what makes the illusion convincing.
Claim
“Most of a CPU is arithmetic.”
Reality
Arithmetic is a small fraction of the die. Caches, branch prediction, buffering and scheduling dominate, because the hard problem is supplying operands, not adding them.
Claim
“If I understand the block diagram, I understand the CPU.”
Reality
The diagram is a teaching device that omits width, ordering and renaming. Believing it literally produces exactly the misconceptions this domain spends the rest of its lessons undoing.

Where the rest of this lives

Programming Languages & Runtime Internals
From source to machine code

Everything the front end fetches was produced by a compiler or JIT, and what it chose to emit determines how much work the front end has to do. That translation step is a domain of its own.