GPUs & Hardware / Accelerators
Why AI runs on massively parallel hardware.
Reviewed by Yuvaraj
A CPU, a GPU, and a TPU are all built from transistors doing arithmetic, but they answer a different question with that silicon. A CPU is engineered to finish one unpredictable task as fast as possible; a GPU is engineered to finish a mountain of identical tasks as fast as possible; a TPU narrows that further, dedicating almost all of its silicon to the single operation that dominates deep learning, matrix multiplication. Which chip wins is not a matter of "newer is faster" but of the shape of the work you hand it.
The whole comparison rests on one distinction. Latency is the time to complete a single task; throughput is the number of tasks completed per unit time. They are not the same knob, and optimizing one often costs the other.
A processor designer has a fixed transistor budget and must decide how to spend it. A CPU spends most of that budget on control and memory: out-of-order execution, branch predictors, speculative execution, and deep caches, machinery whose only job is to keep a few arithmetic units fed so a single instruction stream never stalls. A GPU spends its budget the opposite way: it strips the per-core control logic to the bone and pours the transistors into thousands of arithmetic units, accepting that any one of them is slow and often stalled, because there are enough of them that the aggregate rate is enormous.
For a curious beginner
A CPU is a sports car: one or two passengers, but door to door in minutes. A GPU is a commuter train: slow to start and it stops at every platform, yet it moves thousands of people at once. For a single quick errand, take the car. To move a stadium, the train wins, even though every individual trip is slower.
How it is actually used
Latency is seconds-per-task; throughput is tasks-per-second. CPUs minimize the first with speculation and caches so one thread never waits. GPUs maximize the second by keeping thousands of threads resident and switching to a ready one the instant another stalls on memory, the stall is hidden, not removed.
The underlying mechanism
Little's law ties them together: . You can raise throughput without lowering per-operation latency simply by raising concurrency. That is exactly the GPU strategy, keep enough operations in flight that long memory latencies are fully overlapped by useful work elsewhere.
Ask about this lesson, or about anything in AI. Answers cite the lessons they draw on.
Finished this lesson?
Mark it complete to earn XP, keep your streak, and schedule a review.
A modern CPU core is a masterpiece of latency reduction. It fetches instructions ahead of time, predicts branches (guessing which way an if will go and speculatively executing down that path), reorders instructions to work around stalls, and leans on a deep cache hierarchy so that data an unpredictable program is likely to reuse sits a few nanoseconds away instead of hundreds. Each core also has modest data parallelism through SIMD vector units (SSE, AVX, AVX-512), but the design center is a small number of very capable cores, typically a handful on a laptop, up to dozens on a server.
That machinery is precisely what irregular software needs: parsing, branchy business logic, pointer-chasing data structures, coordination. It is also expensive. A representative 32-core server CPU with AVX-512, clocked around 3 GHz, tops out near 4–6 TFLOP/s of FP32 in practice, respectable, but a small fraction of what an accelerator delivers on the right workload. When the work is one long dependency chain full of branches, the CPU is unbeatable. When the work is a million independent multiply-adds, all that control logic is dead weight.
A GPU is organized as a set of Streaming Multiprocessors (SMs). Each SM holds many simple arithmetic lanes ("CUDA cores"), a large register file, a slice of fast on-chip memory, and a few warp schedulers. Threads are not scheduled individually, they run in lockstep groups of 32 called warps. Every thread in a warp executes the same instruction in the same cycle, each on its own data. This is SIMT: Single Instruction, Multiple Threads.
Two consequences follow directly:
if, the hardware must execute both paths and mask off the inactive lanes. Deeply branchy code wastes most of the warp, which is why control-heavy logic belongs on the CPU.For scale, an NVIDIA H100 (SXM) has 132 SMs and 16,896 FP32 lanes. Its general FP32 rate is roughly 67 TFLOP/s, already about 15× a strong CPU. But the H100 also carries tensor cores: units that multiply small matrices in one hardware step, reaching about 990 TFLOP/s in BF16 (the ~1,979 figure vendors quote assumes structured sparsity, read those with care). Those tensor cores exist for exactly one reason, which the next section makes concrete.
A neural network is, to a first approximation, a stack of matrix multiplications. Multiplying an matrix by a matrix produces output entries, and each entry is an independent dot product, it needs none of the other entries' results. That independence is the property massively parallel hardware feeds on: map one output entry (or one tile of them) to each group of lanes, and thousands compute at once with no coordination.
Independence alone is not enough, though. The deeper reason matmul suits these chips is its arithmetic intensity, the ratio of arithmetic performed to bytes moved from memory. An square matmul costs about floating-point operations but touches only about numbers. For in BF16 that is GFLOP against MB of data, roughly 1,300 FLOP per byte. A chip with thousands of hungry arithmetic units can only stay busy if each byte it fetches feeds hundreds of operations, and large matmul delivers exactly that.
The same math explains slow token generation
Contrast matmul with an elementwise add: two reads and one write per operation is about 0.17 FLOP/byte, hopelessly memory-bound. Generating LLM tokens one at a time is closer to matrix-vector products, whose intensity is also low, so decoding is limited by memory bandwidth, not compute. Big dense matmul is the friendly case; know when your workload is not it.
The processors also disagree about memory. A CPU builds a tall, latency-optimized hierarchy: per-core L1 (tens of KB, a few-cycle access), per-core L2 (a megabyte or two), a shared L3 (tens of MB), then DRAM at hundreds of cycles away with bandwidth of tens to a few hundred GB/s. The bet is that an unpredictable program reuses data, so keeping it close cuts latency.
A GPU makes almost the opposite bet. Per-SM caches are comparatively modest, on an H100, roughly 256 KB of register file and up to 256 KB of combined L1/shared memory per SM, plus a 50 MB shared L2, but the path to main memory is extraordinarily wide: 80 GB of HBM3 at 3.35 TB/s, an order of magnitude more bandwidth than a CPU's DRAM. The GPU tolerates high memory latency (it hides it with warps) in exchange for the raw bandwidth needed to stream operands into thousands of lanes. CPUs optimize the latency of memory; GPUs optimize its bandwidth.
A GPU is still a general parallel computer. A TPU (Tensor Processing Unit, Google's ML accelerator) specializes one step further, organizing its core around a systolic array: a two-dimensional grid of multiply-accumulate (MAC) cells wired directly to their neighbors. Data marches through the grid in lockstep waves, weights held stationary in the cells, activations flowing across, and each cell multiplies, adds the partial sum arriving from its neighbor, and passes the running total along. Operands are reused in space as they ripple through the array, so a matrix multiply is computed with very few trips to memory and almost no instruction-fetch overhead. The TPU's matrix unit (MXU) is a 128×128 systolic array in recent generations (the first TPU used a 256×256 array of 8-bit MACs).
When a TPU helps versus a GPU. The systolic design is efficient precisely when the work is a large, dense matmul with static shapes, run at scale, big-batch training and inference of standard architectures, where the array stays full and its high-bandwidth pod interconnect lets thousands of chips cooperate. A TPU v4 chip delivers about 275 TFLOP/s in BF16 from that array, backed by 32 GB of HBM at ~1.2 TB/s. A GPU tends to win when you need flexibility: dynamic or irregular shapes, custom kernels, sparse or non-matmul operations, mixed workloads, and the breadth of the CUDA ecosystem. Neither is universally faster, the TPU trades generality for density on one operation, and that trade only pays when your workload really is that operation.
Take one concrete kernel: multiply two matrices. That is billion floating-point operations. Dividing the work by each chip's peak rate gives an upper bound on how fast it could finish:
| Processor / unit | Peak throughput (approx.) | Time for 137 GFLOP at peak |
|---|---|---|
| Server CPU (32-core, FP32/AVX-512) | ~4 TFLOP/s | ~34 ms |
| H100 GPU, FP32 (no tensor cores) | ~67 TFLOP/s | ~2.0 ms |
| H100 GPU, BF16 tensor cores | ~990 TFLOP/s | ~0.14 ms |
| TPU v4, BF16 MXU | ~275 TFLOP/s | ~0.50 ms |
Two lessons hide in that table. First, moving the same FP32 work from CPU to GPU is already ~15× faster, that is the "thousands of lanes" effect. Second, switching to the tensor cores' native BF16 buys another ~15×, that is the "purpose-built matmul silicon" effect, the same idea the TPU's array embodies. The two multipliers compound.
Common mistakes