A modern processor core can retire several instructions per nanosecond. A read from main memory
—
This is the memory wall: the ever-widening gap between how fast processors can compute and how fast memory can feed them. The entire memory hierarchy — registers, caches, DRAM, disk — exists to hide that gap. And the reason a hierarchy can work at all comes down to one lucky property of real programs: locality.
Programs do not touch memory at random. They touch it in patterns, and there are two patterns that matter so much they have names:
Temporal locality says keep recently-used data close. Spatial locality says when you fetch one byte, fetch its neighbours too — which is exactly why caches move data in blocks of 64 bytes rather than one byte at a time. Almost every trick in this module is, at heart, a bet that one of these two localities holds.
For decades processor performance improved at roughly
The absolute numbers do not matter; the shape does. One curve pulls away from the other and never comes back. If nothing intervened, programs would spend nearly all of their time waiting on memory. The hierarchy is what intervenes.
No single memory technology is both large and fast — SRAM is fast but tiny and power-hungry, DRAM is roomy but slow, flash is enormous but glacial. So we stack them, small-and-fast on top, large-and-slow at the bottom, and let each level cache the most-used data of the level below it. Locality is what makes the illusion hold: because accesses cluster, a small fast level captures the vast majority of them, and the big slow level is only rarely disturbed.
The magic is that the whole tower appears to run at nearly the speed of the top and at nearly the capacity of the bottom. To the programmer it looks like one flat, fast, gigantic memory — a comfortable fiction assembled from half a dozen honest, limited devices.
How fast does the illusion actually run? For a single level backed by a slower one, the average memory access time (AMAT) is the hit time you always pay, plus the miss penalty you pay only on the fraction of accesses that miss:
Suppose the L1 cache answers in
Four nanoseconds — barely more than the 1 ns cache, nowhere near the 100 ns DRAM. That factor-of-25
improvement over "always hit DRAM" is bought entirely with a
You could — and it would be gloriously fast — but an SRAM cell needs six transistors to a DRAM cell's one (a single transistor plus a tiny capacitor). That makes SRAM roughly an order of magnitude less dense and far more expensive and power-hungry per bit. A 16 GB SRAM main memory would be enormous, cost a fortune, and cook itself. The hierarchy is an economic compromise as much as a performance one: we spend our precious fast SRAM only where locality guarantees it will be reused constantly, and let cheap dense DRAM hold the long tail. Fast, big, cheap — pick two, then hide the seam.
Beginners sometimes talk as if the cache "creates" locality. It does not. The cache exploits locality that the program already has (or lacks). A cache-friendly loop that walks an array in order gets near-perfect spatial locality; the same loop striding backwards by 4096 bytes, or chasing pointers through a linked list scattered across the heap, may get almost none — and no cache can save it. This is why how you write your loops and lay out your data can change performance by 10× on identical hardware. The hierarchy rewards locality; it cannot manufacture it.
Everything that follows is a way of making the illusion faster or wider. Next we open up the