Yes, GPUs have caches — and if you carry your
Four levels, each roughly an order of magnitude bigger and slower than the last:
| Level | Size (representative) | Visible to | Latency (approx.) |
|---|---|---|---|
| Register file | 256 KB per SM | one thread (its own registers) | ~1 cycle |
| Shared memory / L1 | 128 KB per SM (one SRAM pool) | block (shared) / SM (L1) | ~20–30 cycles |
| L2 cache | a few MB, in slices | the whole chip | ~200 cycles |
| GDDR / HBM DRAM | tens of GB | everything | ~400–600 cycles |
The shapes are CPU-familiar; the per-thread arithmetic is not. Do it once and the whole philosophy of GPU caching falls out. A mainstream part has, say, 2 MB of L2 shared by roughly 100,000 resident threads:
Twenty bytes. Not twenty kilobytes — twenty bytes, five floats, per thread. The per-SM L1 fares little better: 128 KB across up to 2,048 resident threads is 64 B each. And now the punchline of the whole hierarchy: the register file, at 256 KB per SM, is bigger than the L1 and gives each thread 128 B of truly private, single-cycle storage. Per thread, the GPU pyramid is upside down: registers are the roomiest fast storage a thread will ever see, and each cache level below offers it less. Compare a CPU core: 32 KB of L1 split between 2 SMT threads is 16 KB each — about a thousand times the GPU figure.
Plotted per thread — the only fair way to compare machines with such different thread counts — the hierarchy looks like this:
This chart is why the rest of the lesson keeps repeating one sentence: on a GPU, latency is hidden by warps, and caches are for saving bandwidth.
If a cache cannot hold anyone's working set, what is it for? Catching sharing and spillover — the reuse that exists between threads rather than within one:
Notice what is absent: no per-thread latency story. A hit in the GPU's L2 still costs ~200 cycles — useless for making one thread feel fast, which is fine, because no one is asking it to. Ready warps cover the 200 cycles; the L2's contribution is that DRAM's bandwidth wasn't spent.
One honest paragraph about coherence, because CPU habits expect it: the per-SM L1s are not kept coherent with each other. If SM 3 writes a value that SM 40 then reads from its own stale L1, the hardware will not fix it for you. The discipline is simple and GPU-shaped: threads in different blocks communicate through global memory only at kernel boundaries (a new kernel launch invalidates the L1s and sees everything), or via atomics, which operate at the L2 — the one point every SM agrees on. Writes typically go through the L1 (write-through, no write-allocate) to the L2 precisely so that the little lies the L1s tell stay read-only and short-lived.
The per-thread arithmetic predicts something testable: a working set that a lone thread could cache comfortably becomes uncacheable when ten thousand siblings share the same SRAM. One tiny direct-mapped cache, two worlds:
Identical reuse in the program — every line is touched ten times in both worlds — yet the crowd gets almost nothing: 8192 × 4 = 32,768 distinct lines cycle through 1,024 slots, and every revisit finds its line evicted. Shrink the crowd to 128 threads (512 lines total) and the hit rate snaps back. That is the arithmetic of 20 bytes per thread, acted out.
Recent flagship GPUs ship tens of megabytes of L2 (or an extra "infinity" level of last-level cache) — a strange investment in a structure this lesson keeps calling tiny. The economics are on the bandwidth side: every byte served from L2 is a byte GDDR/HBM doesn't ship, and DRAM bandwidth is the most expensive commodity on the board — wide buses, exotic packaging, stacked dies, watts. Growing the L2 is cheaper than growing the memory bus, so vendors buy effective bandwidth with SRAM: a 50% L2 hit rate doubles what the DRAM system appears to deliver. The cache grew, but its job description didn't — it is a bigger filter, not a latency machine.
A classic wasted afternoon: restructuring a kernel so each thread revisits its own data "while
it's hot in L1" — CPU-style temporal-locality tuning. But your thread's share of the L1 is ~64
bytes; by the time the warp scheduler has cycled through a few dozen other warps, "your" lines are
long gone. On a GPU you engineer reuse in the two memories you actually control:
registers (keep accumulators and loop-carried values in per-thread variables —
128 B of guaranteed residence) and