Seyed Masoud Hosseini · Overview · Study log · Ideas · Transcript · RSS feed
Performance Engineering of Software Systems · Lecture 20 of 23 · 1:23:03
Lecture 20: Speculative Parallelism and Leiserchess
Study guide
What this lecture covers
The lecture asks how to get parallel speedup from code, like alpha-beta search, that is inherently serial because pruning depends on the order of evaluation. The answer is speculative parallelism: guessing that work will be needed, doing it in parallel anyway, and aborting cleanly when the guess is wrong. The second half applies this directly to the Leiserchess course project, walking through parallel alpha-beta search and a long list of optimizations available in the codebase.
This lecture continues directly from the prior lecture's introduction to the Leiserchess project and its search code. After watching, you can explain why naive parallel alpha-beta wastes work, describe the young-siblings-wait technique for parallelizing it safely, and recognize which of several existing search optimizations (transposition table, killer moves, iterative deepening, endgame databases, null-move pruning, Zobrist hashing) matter most for the project.
Key ideas
- Speculative parallelism: spawning parallel work that a serial execution might not have performed, betting it will be needed, with a way to abort it cheaply if it turns out not to be.
- Threshold sum example: a short-circuiting parallel sum uses an abort flag, checked before being set (to avoid unnecessary cache-line contention) and requiring no memory fence, since the flag only ever transitions false-to-true and either observed value keeps the algorithm correct.
- Rule of thumb for speculation: don't spawn speculative work unless there's little other parallelism available and a good chance the work will be needed; speculating on all branches of a minimum-finding search, for example, can look like superlinear speedup but is really wasted work compared to a better serial algorithm.
- Best-ordered game trees and the young-siblings-wait algorithm: in a best-ordered tree a node's effective branching factor is either 1 (a cutoff) or maximal (full exploration); the parallelization strategy searches the first child, and only if it fails to produce a cutoff does it speculatively search the remaining "young sibling" children in parallel.
- Abort propagation: each node tracks whether an ancestor has aborted; workers periodically (not on every step) check up the tree so wasted speculative work stops without paying the cost of checking on every node.
- Shared search data structures under parallelism: the transposition table, killer-move table, and best-move table are all shared, mutable structures, and each requires a separate decision about locking, per-worker replication, or accepting a benign race for performance.
- Iterative deepening: searching depth 1, then 2, then 3, and so on costs only a constant factor more work in total, but produces progressively better move-ordering information (via the transposition table) that makes each deeper search prune far more effectively.
- Zobrist hashing: a position's hash is the XOR of per-piece-per-square random values; because XOR is its own inverse, moving a piece updates the hash with just two XOR operations instead of recomputing from scratch.
- Distance-to-mate encoding: endgame databases and mate scores must track distance to mate, not just win/loss/draw, otherwise search can cycle indefinitely among winning positions without ever converging on checkmate.
Walkthrough
Speculative parallelism and the threshold-sum example (2:02)
The lecture opens by noting that code like alpha-beta search is inherently serial, since parallelizing it naively causes cutoffs to be missed and wasted work to be performed. It introduces speculative parallelism as the general fix, then works through a short-circuiting parallel sum: strip-mining reduces the overhead of checking a threshold every iteration, and a shared abort flag lets parallel branches stop early. The lecture explains why checking the flag before writing it avoids unnecessary cache contention, and why no memory fence is needed since the flag only transitions one direction.
When speculation pays off (12:20)
The lecture states the rule of thumb: only spawn speculative work when there's little other parallelism available and a good chance it will be needed, illustrating with a cautionary example of researchers claiming superlinear speedup from speculatively searching for a minimum in parallel, when a better serial algorithm (dovetailing) would have been more efficient.
Parallelizing alpha-beta with the young-siblings-wait algorithm (14:24)
Building on the Knuth-Morris result that best-ordered alpha-beta search examines roughly the square root of the naive node count, the lecture presents the young-siblings-wait technique from a paper by Burkhardt and colleagues: search the first child serially, and only if it fails to generate a cutoff, speculatively search the remaining children in parallel, since a best-ordered tree either fully explores all children or cuts off after the first. Each node periodically checks up the tree for an aborted ancestor so unnecessary speculative work can stop.
Managing shared search data structures (22:34)
The lecture discusses three shared, mutable data structures the parallel search touches: the transposition table, killer-move table, and best-move table, each requiring its own choice between locking, replication, or accepting a race. Leiserson recounts his own program's decision, in a past world computer chess championship, to run with an unguarded race on the transposition table after estimating the odds that a race actually changes the outcome of a game were vanishingly small, since locking every access would have been more costly. He emphasizes having a way to disable speculation and transposition-table access entirely so other parts of the program can be tested deterministically.
Iterative deepening, endgame databases, and other search techniques (38:54)
The lecture explains why iterative deepening (searching depth 1, 2, 3, ... instead of jumping straight to the target depth) is worthwhile: it costs only a constant factor of extra total work but yields much better move ordering at each depth via the transposition table. It covers endgame databases (illustrated with king-versus-king endings), stressing that a database must store distance-to-mate rather than a simple win/loss/draw value to avoid the search cycling between winning positions forever. It also covers quiescence search, null-move pruning (and its failure mode in zugzwang-like positions), and late-move reductions, which search moves further down a sorted move list at reduced depth since they're less likely to be good.
Zobrist hashing and the transposition table in detail (54:11)
The lecture re-explains Zobrist hashing: a table of precomputed random numbers indexed by square, piece type, and orientation, XORed together to hash a position, updated incrementally with just two XORs per move since XOR is its own inverse. It also covers the transposition table's quality score (based on search depth) and the special handling needed to convert a stored "mate in N" value into the correct mate distance from the root of the current search.
Board representation and the laser-coverage heuristic (1:02:24)
The lecture surveys board representation choices, bit boards using shift operations for fast move generation versus piece lists that shrink as the game progresses, and recommends refactoring all board accesses through a function before changing representation so the old and new versions can be validated against each other. It closes with a detailed walkthrough of the laser-coverage evaluation heuristic, which estimates how close a side's laser can get to the opponent's king across all one-move lookahead paths, and flags it as one of the most expensive parts of the evaluation function worth optimizing, along with move sorting.
Before you watch
- Watch the prior lecture in this course, "Leiserchess Codewalk," which introduces the game, the board and move representation, and alpha-beta and principal variation search.
- Familiarity with races, locks, and memory fences from earlier lectures in this course is assumed, since the speculative-parallelism examples depend on them.
- Basic exposure to XOR-based bit tricks helps with the Zobrist hashing explanation.
Check your understanding
- Why is naive parallelization of alpha-beta search likely to waste processor time compared to serial execution?
- In the young-siblings-wait algorithm, under what condition does the search speculatively parallelize the remaining children, and why does that condition follow from best move ordering?
- Why doesn't the threshold-sum abort flag need a memory fence, even though it's read and written by multiple parallel branches?
- Why is it cheaper to search depth 1, then 2, then 3, and so on (iterative deepening) than to search directly to the target depth, despite appearing redundant?
- Why must an endgame database store distance-to-mate rather than a simple win/loss/draw value?
Chapters
- 0:00 <Untitled Chapter 1>
- 6:14 Thresholding a Sum in Parallel
- 6:44 Divide-and-Conquer Loop
- 10:25 Short-Circuiting in Parallel
- 12:06 Speculative Parallelism
- 15:21 Review: Alpha-Beta Analysis
- 18:20 Parallel Alpha-Beta
- 19:37 Abort Mechanism
- 21:05 Problem with Young Siblings Wait
- 21:40 Alpha-Beta Search: Example
- 22:12 Tips for Parallelizing Leiserchess
- 37:11 Opening Book
- 39:06 Iterative Deepening
- 42:00 Endgame Database
- 45:28 Quiescence Search
- 46:03 Null-Move Pruning
- 49:01 Other Search Heuristics
- 50:48 Transposition Table
- 54:32 Zobrist Hashing
From the YouTube description
MIT 6.172 Performance Engineering of Software Systems, Fall 2018
Instructor: Charles Leiserson
View the complete course: https://ocw.mit.edu/6-172F18
YouTube Playlist: https://www.youtube.com/playlist?list=PLUl4u3cNGP63VIBQVWguXxZZi0566y7Wf
Prof. Leiserson discusses speculative parallelism and its applications in parallel alpha-beta search and jamboree search. The lecture ends with a discussion of computer-chess programs.
License: Creative Commons BY-NC-SA
More information at https://ocw.mit.edu/terms
More courses at https://ocw.mit.edu
← Lecture 19: Leiserchess Codewalk · Lecture 21: Tuning a TSP Algorithm →
