← tonia.ai
Computer Architecture

Pipelining from first principles

How overlapping instructions raises throughput, what hazards are and what they cost, and how dependences between instructions decide how full a pipeline can stay. Two calculators let you time a pipeline and trace the dependences in real code.

Part A

Why pipeline?

The assembly-line idea

Doing laundry takes four steps: wash, dry, fold, put away. If each takes 30 minutes and you finish one load completely before starting the next, four loads take 8 hours. If you start the second wash as soon as the first load moves to the dryer, all four steps stay busy and the same four loads finish in 3.5 hours.

No single load finished faster; each still took 2 hours. What improved is throughput: once the pipeline is full, a load finishes every 30 minutes. A processor pipeline works the same way. Instruction execution is split into stages, and a new instruction enters the first stage every clock cycle while older instructions move along behind it.

Load6:006:307:007:308:008:309:00
Load AWashDryFoldStore
Load BWashDryFoldStore
Load CWashDryFoldStore
Load DWashDryFoldStore

The five-stage pipeline

The classic RISC pipeline, used in MIPS, early Arm cores and most textbook RISC-V designs, has five stages. Pipeline registers between stages (IF/ID, ID/EX, EX/MEM, MEM/WB) hold each instruction's values and control signals as it advances, so every stage can work on a different instruction in the same cycle. Every instruction passes through all five stages, even ones it does not need, which keeps the timing uniform.

StageWork donelwaddswbeq
IF FetchRead the instruction at PC; PC + 4✓✓✓✓
ID DecodeDecode; read source registers; sign-extend the immediate✓✓✓✓
EX ExecuteALU operation or address calculation; compare for branchesAddressSumAddressCompare, target
MEM MemoryRead or write data memoryRead–Write–
WB Write backWrite the result to the register file✓✓––

Timing and speedup

Cycles for n instructions on a k-stage pipeline = k + (n − 1)

The first instruction needs k cycles to fill the pipeline; after that, one instruction finishes per cycle. For long instruction streams the ideal speedup approaches k. Three things keep real pipelines below that:

  • Unbalanced stages. The clock must fit the slowest stage, so faster stages sit idle for part of every cycle.
  • Register overhead. Each pipeline register adds setup time and clock skew to every cycle.
  • Hazards. Stalls add cycles in which no instruction finishes (Part B).

Take stage delays of 200 ps for fetch, 100 ps for register read, 200 ps for the ALU, 200 ps for data memory and 100 ps for write-back. An unpipelined design that runs one load per 800 ps cycle becomes a pipeline with a 200 ps clock, so the speedup is 800 / 200 = 4, not 5, because the two 100 ps stages waste half their cycle.

Pipeline timing calculator

3.98× speedup

Each bar is one clock cycle. Teal: time the stage spends working. Copper: register overhead. Pale: time it sits idle waiting for the clock. Try splitting the 200 ps stages in two, or adding 20 ps of overhead.

Part B

Hazards

Three kinds of hazard

A hazard is any situation that prevents the next instruction from entering the pipeline in its planned cycle. The pipeline must stall, inserting a bubble (an empty slot that does no work), until the hazard clears.

HazardCauseEffect if untreated
StructuralTwo instructions need the same hardware in the same cycleOne must wait
DataAn instruction needs a value an earlier instruction has not yet writtenIt would read a stale value, so it must wait
ControlThe address of the next instruction depends on a branch not yet resolvedWrong-path instructions must be discarded, or fetch must wait

Structural hazards

If instructions and data share one memory port, a load in MEM and a fetch in IF collide every time. Pipelined processors avoid this with separate instruction and data caches. The register file is read in ID and written in WB in the same cycle, so it is designed to write in the first half of the cycle and read in the second, or given separate read and write ports. Long operations such as floating-point division are often not fully pipelined, so two divides in a row still contend for one unit; designers accept this when the operation is rare enough.

Data hazards

In this sequence, sub reads x1 in ID (cycle 3), but add does not write it until WB (cycle 5):

Instructionc1c2c3c4c5c6c7c8
add x1, x2, x3IFIDEXMEMWB
sub x4, x1, x5IFIDstallstallEXMEMWB

With a register file that writes before it reads within a cycle, sub can read the correct value in cycle 5, so it repeats ID for two extra cycles. Hardware that detects this and holds the instruction is called an interlock.

Control hazards

A conditional branch in the five-stage pipeline is not resolved until EX. By then, two more instructions have already been fetched from the path that may be wrong. The simplest fix stalls fetch until the outcome is known, which costs 2 cycles on every branch. Since roughly 15 to 20% of instructions in typical integer code are branches, that alone adds 0.3 to 0.4 cycles to every instruction's average. Control hazards grow with pipeline depth, because the branch resolves further from the front.

What stalls cost

CPI = 1 + stall cycles per instruction  ·  Speedup = Pipeline depth / (1 + stall cycles per instruction)

The second formula assumes perfectly balanced stages. Suppose a five-stage pipeline with no special hazard hardware runs code in which 30% of instructions use the result of the instruction just before (2 stalls each), 10% use a result from two instructions back (1 stall each), and 15% are branches (2 stalls each):

Stalls per instruction = 0.30 × 2 + 0.10 × 1 + 0.15 × 2 = 1.0, so CPI = 2.0 and the speedup is 5 / 2 = 2.5 instead of 5. Hazards erased half the benefit of pipelining, which is why so much processor design effort goes into removing them.

Part C

Data dependences

Types of dependence

A dependence is a property of the program: two instructions must keep their order to produce the right result. A hazard is a property of the pipeline: whether that dependence, at that distance, would be violated by overlapping the instructions. The same dependence can cause a hazard on one pipeline and none on another.

DependenceAlso calledExampleMatters when
True (data)RAW, read after write
add x1, x2, x3
sub x4, x1, x5
Always: a value flows from one instruction to the next
AntiWAR, write after read
sub  x4, x1, x5
addi x1, x6, 1
Only if a later write can complete before an earlier read, as in out-of-order execution
OutputWAW, write after write
add  x1, x2, x3
addi x1, x6, 1
Only if writes can complete out of order, as with mixed-latency units
Control
beq x1, x0, skip
add x2, x2, x3
Always: whether add runs depends on the branch

Anti and output dependences are name dependences: no value passes between the instructions, they just reuse a register name. In the simple in-order five-stage pipeline, reads always happen in ID and writes in WB, in program order, so only true dependences cause stalls.

Dependence distance

The number of instructions between a producer and its consumer decides the stall. Without any hazard-removal hardware, in the five-stage pipeline:

DistanceExampleStall cycles
1Consumer immediately follows the producer2
2One independent instruction in between1
3 or moreTwo or more independent instructions in between0

This is why the order of instructions matters so much: placing independent work between a producer and its consumer hides the latency for free.

Dependence analyzer

Enter RISC-V code or pick an example. The analyzer lists every dependence and shows the resulting pipeline timing with interlocks only (no forwarding). Supported: add sub and or xor sll srl sra slt sltu mul div rem, the matching -i forms, and loads and stores.

13 cycles

Assumes separate instruction and data memories, straight-line code, and a register file that writes in the first half of a cycle and reads in the second.

Chains and parallelism

A program's dependences form a graph. The longest path through it, the critical path, sets a lower bound on execution time no matter how the instructions are scheduled. Compare the "Dependent chain" and "Two chains interleaved" examples: the second does twice as much work in only a few more cycles, because instructions from one chain fill the gaps left by the other.

How much independent work real programs contain was measured in limit studies. Wall found that typical programs expose only a handful of independent instructions at a time; Austin and Sohi traced dynamic dependence graphs to see where the parallelism lies; and Lam and Wilson showed that control dependences, more than data dependences, limit how much can be found. These results shaped everything from compiler scheduling to how wide processors are built.

Go further

Resources

Interactive tools and references

Peer-reviewed reading

  • Ramamoorthy, C. V., & Li, H. F. (1977). Pipeline architecture. ACM Computing Surveys, 9(1), 61–102.A comprehensive early survey of pipelining principles and hazards.doi.org/10.1145/356683.356687
  • Patterson, D. A., & Ditzel, D. R. (1980). The case for the reduced instruction set computer. ACM SIGARCH Computer Architecture News, 8(6), 25–33.Why simple instructions suit pipelining.doi.org/10.1145/641914.641917
  • Radin, G. (1982). The 801 minicomputer. Proc. ASPLOS I, 39–47.An early design built around a one-instruction-per-cycle pipeline.doi.org/10.1145/800050.801824
  • Hennessy, J., et al. (1982). MIPS: A microprocessor architecture. Proc. MICRO-15, 17–22.The pipeline behind the classic five-stage model, with hazards handled by software.doi.org/10.1145/1014194.800930
  • Kunkel, S. R., & Smith, J. E. (1986). Optimal pipelining in supercomputers. Proc. ISCA, 404–411.How register overhead and hazards limit useful pipeline depth.doi.org/10.1145/17356.17403
  • McFarling, S., & Hennessy, J. (1986). Reducing the cost of branches. Proc. ISCA, 396–403.Quantifies control hazards and early ways to reduce them.doi.org/10.1145/17356.17402
  • Lee, J. K. F., & Smith, A. J. (1984). Branch prediction strategies and branch target buffer design. IEEE Computer, 17(1), 6–22.How often branches occur and what they cost a pipeline.doi.org/10.1109/MC.1984.1658927
  • Smith, J. E., & Pleszkun, A. R. (1988). Implementing precise interrupts in pipelined processors. IEEE Transactions on Computers, 37(5), 562–573.Keeping a pipeline's state consistent when an instruction faults.doi.org/10.1109/12.4607
  • Wall, D. W. (1991). Limits of instruction-level parallelism. Proc. ASPLOS IV, 176–188.How much independent work real programs contain.doi.org/10.1145/106972.106991
  • Austin, T. M., & Sohi, G. S. (1992). Dynamic dependency analysis of ordinary programs. Proc. ISCA, 342–351.Dependence graphs of running programs and where parallelism hides.doi.org/10.1145/139669.140395
  • Lam, M. S., & Wilson, R. P. (1992). Limits of control flow on parallelism. Proc. ISCA, 46–57.Why control dependences limit overlap more than data dependences.doi.org/10.1145/139669.139702