Out-of-order execution
What is out-of-order execution?
WHY do we need this?
- In-order processors stall when they hit a data dependency or cache miss
- Modern instructions have vastly different latencies: register ops (1 cycle), L1 cache (4 cycles), memory (100+ cycles)
- Without OoOE, the CPU wastes cycles waiting even when independent work exists
HOW does it work? The CPU separates the instruction lifecycle into phases that can operate independently:
- Fetch/Decode (in-order): Instructions enter the pipeline
- Dispatch (in-order): Instructions allocated to reservation stations
- Execute (OUT-OF-ORDER): Instructions fire when operands ready
- Commit/Retire (in-order): Results written back in program order
The Tomasulo algorithm foundation
Modern OoOE traces back to Tomasulo's algorithm (IBM 360/91, 1967). Let's derive the key insight from first principles.
The problem: Register renaming and dynamic scheduling.
Consider this code:
R1 = R2 + R3 ; (I1)
R4 = R1 * R5 ; (I2) - depends on I1
R1 = R6 - R7 ; (I3) - WAW hazard with I1
R8 = R1 + R9 ; (I4) - depends on I3, NOT I1
In-order execution: I2 waits for I1, I3 waits for I2, I4 waits for I3 → serial execution.
The insight: The two uses of R1 are different logical values. If we rename them:
T1 = R2 + R3 ; (I1) renamed
R4 = T1 * R5 ; (I2)
T2 = R6 - R7 ; (I3) renamed
R8 = T2 + R9 ; (I4)
Now I3 and I1 can execute in parallel! I4 depends only on I3, not I1.
WHY this step? By breaking the false dependencies, we expose the true data-flow graph. The CPU can now issue any instruction whose inputs are ready.
Reservation stations and execution
Derivation of the ready condition:
Let instruction require operands . Each operand is either:
- Ready: value is in the reservation station
- Waiting: tagged with producer instruction
When producer completes, it broadcasts (tag: Pj, value: V) on the CDB. All reservation stations snoop the CDB and:
WHY broadcast? Multiple instructions might wait on the same result. Broadcasting to all stations in parallel avoids sequential wakeup delays.
The reorder buffer (ROB)
The problem: Out-of-order execution creates out-of-order completion. But we need precise exceptions: if instruction 5 faults, instructions 1-4 must commit, 6+ must not.
Derivation of commit logic:
Let ROB entries be in program order. At the head :
If :
- Flush all entries after
- Roll back architectural state to 's input
- Signal exception to OS
WHY in-order commit? To maintain the illusion that instructions executed sequentially. External observers (memory system, interrupts, debuggers) see results as if the program ran in-order.
Common mistakes
Memory model interaction
How OoOE interacts with multi-core:
Each core's OoOE engine maintains single-threaded illusion. But caches are shared/coherent. The memory consistency model defines what reorderings are visible across cores.
For x86 TSO, the allowed and forbidden reorderings are:
- Loads are NOT reordered with older loads (Load→Load order preserved)
- Loads MAY pass older stores to a different address (Store→Load reordering allowed; this is the one relaxation TSO permits)
- Stores are NOT reordered with older stores (Store→Store order preserved, enforced at commit)
- Stores are NOT reordered with older loads (Load→Store order preserved)
WHY these rules? Balance performance (allow the common Store→Load relaxation via the store buffer) vs. programmer sanity (preserve intuitive ordering everywhere else).
Performance metrics
The ILP wall: typical programs have ~2-3 independent instructions per cycle on average. Even perfect OoOE hits this limit. Modern CPUs compensate with:
- Wider issue (4-6 wide dispatch)
- Deeper speculation (branch prediction)
- Simultaneous multithreading (SMT/Hyper-Threading)
Connections
- 5.1.01-Pipelining: OoOE extends pipelining by decoupling stages
- 5.3.01-Superscalar-architecture: OoOE enables superscalar (multiple issue per cycle)
- 5.3.03-Speculative-execution: OoOE + branch prediction = speculative execution
- 5.3.04-Register-renaming: The RAT mechanism in detail
- 5.4.01-Cache-coherence: How OoOE respects MESI/MOESI in multicore
- 5.5.02-Memory-consistency-models: TSO, relaxed models, and fence instructions
- 6.2.03-Branch-prediction: Predicting control flow to keep the window full
- 7.1.01-Instruction-level-parallelism: Theoretical limits (data-flow graphs)
Recall Explain to a 12-year-old
Imagine you're doing homework with 5 problems. Problem 1 needs a book from the library (your parent will bring it in 10 minutes). Problem 2, 3, 4 are easy math you can do now. Problem 5 needs problem 1's answer.
Bad strategy (in-order): Wait for problem 1 (10 min), do it, do 2, 3, 4, then 5. Total: 10 + 1 + 1 + 1 = 14 minutes.
Smart strategy (out-of-order): Do problems 2, 3, 4 right now (3 min). When the book arrives, do 1 (1 min), then 5 (1 min). Total: 3 + 1 + 1 = 5 minutes.
You finish 3× faster! The CPU does the same: while waiting for slow memory (the "library book"), it works on other instructions (the "easy math"). It keeps the final answers in the correct order so the teacher (the programmer) never knows you did them out-of-order.
#flashcards/hardware
What is the key difference between in-order and out-of-order execution?
What are the three types of hazards, and which can register renaming eliminate?
What is the purpose of the reorder buffer (ROB)?
How does a reservation station know when an instruction is ready to execute?
Under x86 TSO, which single reordering is allowed?
What limits IPC scaling even with infinite instruction window size?
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Dekho, modern CPU ka ek kamaal ka trick hai jo core idea hai out-of-order execution ka. Normally hum sochte hain ki processor jis order mein humne instructions likhe, usi order mein execute karega. Lekin actually mein aisa nahi hota! CPU smart hai — agar ek instruction slow operation ka wait kar raha hai (jaise memory se data laana, jismein 100+ cycles lag sakte hain), toh processor idle nahi baithta. Woh dusre instructions ko dhoondhta hai jinke operands ready hain aur unhe abhi execute kar deta hai. Bilkul restaurant kitchen jaisa — agar ek dish oven mein wait kar rahi hai, toh chef khaali khada nahi rehta, woh doosri dishes banane lag jaata hai jo abhi ho sakti hain. Aur haan, programmer ko lagta hai sab kuch order mein hi ho raha hai, kyunki final results architectural state mein sahi order mein commit hote hain — yeh illusion maintain rehta hai.
Ab yahaan ek important concept aata hai — register renaming. Kai baar do instructions same register (jaise R1) use karte hain, lekin actually mein woh alag-alag logical values hote hain. Iss reuse ki wajah se "false dependencies" ban jaati hain (WAR aur WAW hazards), jo unnecessarily instructions ko serial bana dete hain. Trick yeh hai ki CPU internally bahut saare physical registers rakhta hai (~168) jabki programmer ko sirf 16-32 architectural registers dikhte hain. Register Alias Table (RAT) inhe dynamically map karta hai. Jab hum R1 ke do alag uses ko T1 aur T2 mein rename kar dete hain, toh false dependency khatam ho jaati hai aur woh instructions parallel mein chal sakte hain! Sirf true dependency (RAW — jab ek instruction dusre ka result padhta hai) hi bachti hai, jo genuinely reorder nahi ki ja sakti.
Yeh sab matter kyun karta hai? Kyunki performance ka pura khel throughput ka hai — execution units ko busy rakhna hai, waste cycles nahi hone dene. Reservation stations woh buffers hain jahaan instructions apne operands ka wait karte hue baithte hain, aur woh Common Data Bus (CDB) ko continuously "snoop" karte rehte hain. Jaise hi koi producer instruction apna result broadcast karta hai, saare waiting instructions parallel mein apne operands update kar lete hain — isiliye broadcast use hota hai, taaki sequential wakeup ki delay na ho. Yeh Tomasulo algorithm (1967, IBM 360/91) se aaya hai aur aaj bhi har modern processor ki foundation hai. Agar tum hardware ya computer architecture mein aage badhna chahte ho, toh yeh concept samajhna zaroori hai, kyunki yahi real-world CPUs ko itna fast banata hai.