Computer Architecture
How software actually executes on real hardware — and why moving data usually costs more than computing with it. Not a hardware course: a way of reading your own code that explains why two O(n) loops can differ tenfold.
What do you want to understand?
What actually happens between sum += arr[i] and a number changing in a register — and which part of it is expensive?
Source code to silicon
Every lesson sits somewhere on this chain, and names which end of it your intuition came from.
Flagship experiences
Learn → visualize → execute → inspect → measure → break → optimize.
One arr[i] from address arithmetic through the TLB, three cache levels and the memory controller — with the cost accumulating as you open each level.
One ADD through fetch, decode, rename, schedule, execute, writeback and retire — and why no single stage is the story.
Set size, line size, associativity and access pattern. Find the stride that thrashes, the working set that fits, and the difference between a conflict and a capacity miss.
A decision tree from counters to cause: stalling or working, waiting on memory or on a dependency, bandwidth or latency.
Twelve sets of counters with the cause unlabelled. Read the evidence and name what the hardware is doing.
Sixteen questions with progressive answers, and the red flags that separate a memorised fact from a mental model.
Learning modules
How arithmetic emerges from logic: binary and two's complement, why floating point approximates, gates, adders, and the step from combinational logic to stored state.
The parts that execute an instruction: registers as the fastest storage you have, the ALU, the datapath they sit on, the control unit that steers it, and why clock speed is not performance.
The contract between software and hardware — and the distinction that most performance arguments get wrong: the same ISA is implemented by wildly different microarchitectures.
Fetch, decode, execute, write back — then the pipeline that overlaps them, the hazards that break the overlap, and the forwarding and stalls that patch it up.
A CPU cannot afford to wait to find out where a branch goes, so it guesses. What that buys, what a misprediction costs, and why unpredictable data hurts more than extra work.
Modern CPUs are throughput machines: many instructions in flight, executed as their inputs become ready, retired in program order. Renaming, superscalar issue, ILP and what IPC actually tells you.
One instruction, many elements. What makes a loop vectorizable, what stops the compiler from doing it, and where data-level parallelism sits among the other kinds.
The deepest module, because this is where most real programs spend their time. Lines, locality, associativity, replacement, thrashing and prefetching — the machinery behind "why is this loop slow".
Past the last-level cache: how DRAM is organized, why latency and bandwidth are different resources, and how to tell a bandwidth-bound workload from a latency-bound one.
Where the bytes actually sit: alignment and padding, endianness, address arithmetic, why an array beats a linked list at equal complexity, and array-of-structs versus struct-of-arrays.
The hardware half of a mechanism the OS owns: the MMU that translates, the page tables it walks, the TLB that caches translations, and the protection bits that make isolation possible.
What changes when there is more than one core: hardware threads versus OS threads, the coherence protocol keeping caches consistent, false sharing, NUMA and why moving a thread costs cache.
Why the order you wrote is not the order the machine performs, what a barrier actually constrains, and the hardware primitives — compare-and-swap and friends — every lock is built from.
How the world outside the CPU gets in: interrupts against polling, DMA moving bytes without the CPU copying them, the path to storage, and why a CPU cache is not the OS page cache.
Throughput hardware and its price: why GPUs win on wide regular work, why transfers and divergence undo it, and what specialized accelerators trade away to be fast at one thing.
Reading the machine: performance counters, CPI, telling compute-bound from memory-bound, and every way a microbenchmark will lie to you about frequency, caches and dead code.
Cache-aware algorithms and tiling, what the compiler did before the CPU saw your code, side channels as a consequence of speculation, and the hardware under virtual machines and containers.
Nothing here is universal
§224 — cache sizes, latencies, policies and ordering rules all vary. Every claim says what it is specific to.
True of this instruction set; another may not have the concept.
True of one implementation; the next generation may differ.
A deliberately reduced model, with the omissions named.
Produced by a model here — faithful shape, invented magnitudes.
You will not find an exact latency table here. Publishing "L1 is 1.2 ns" would be wrong on every machine except the one it was measured on, and numbers outlive their caveats. What transfers is the ratio — a register is one unit, a cache level is a few, memory is hundreds — and that is what the cost scales show.