Seyed Masoud Hosseini · Overview · Study log · Weekly summaries · Ideas · Search · Transcript · RSS feed

Performance Engineering of Software Systems · Lecture 15 of 23 · 1:21:47

15. Cache-Oblivious Algorithms

15. Cache-Oblivious Algorithms on YouTube

Study guide

What this lecture covers

The previous lecture introduced cache-oblivious matrix multiply. This lecture extends the idea to two more problems: simulating the heat equation with a stencil computation, and sorting. For heat diffusion, it derives a naive looping implementation, measures its poor cache behavior, and replaces it with a trapezoidal divide-and-conquer decomposition that is cache-oblivious in any number of dimensions. For sorting, it walks from ordinary two-way merge sort through cache-aware multiway merge sort (tuned with a "voodoo parameter") to funnel sort, a cache-oblivious algorithm with the same optimal cache complexity.

Along the way, live demos compare looping and trapezoidal code in serial and parallel settings, exposing a surprising result about hardware prefetching and memory bandwidth, and the lecture closes with a practical checklist for diagnosing why a parallel program isn't speeding up as expected.

Key ideas

  • Stencil computation: an update rule, like the finite-difference approximation of the heat equation, that recomputes each grid point from a small fixed neighborhood of points at the previous time step.
  • Trapezoidal decomposition: cache-oblivious stencil code divides the space-time domain into trapezoids using space cuts (slope -1/+1, when a trapezoid is too wide) and time cuts (horizontal, when too tall), recursing until a trapezoid's base fits in cache.
  • D-dimensional cache-oblivious bound: the trapezoidal algorithm achieves Theta(NT / (M^(1/D) * B)) cache misses versus Theta(NT/B) for naive looping, an improvement by a factor of M^(1/D).
  • Parallel space cut: a "V-shaped" cut splits a wide trapezoid into two independent trapezoids that run in parallel plus a dependent one that runs after, giving the stencil recursion some parallelism without breaking correctness.
  • Hardware prefetching versus cache-obliviousness: in the serial, single-core demo the cache-oblivious code has far fewer misses but only a modest speedup over looping code, because the looping code's regular access pattern lets hardware prefetching hide much of its memory latency; in parallel, prefetching competes with other cores for memory bandwidth, so the cache-oblivious code's advantage grows.
  • Speedup bottleneck checklist: check for insufficient parallelism, scheduler overhead (diagnosable via work/span and tools like Cilkscale), memory bandwidth contention (diagnosable by running P copies of the serial code in parallel), and lock or true/false-sharing contention (hardest to detect).
  • Multiway merge sort: merging R sorted sub-arrays at once with a tournament tree, tuned so R = Theta(M/B), saves a factor of Theta(B log M) in cache misses over binary merge sort, at the cost of being cache-aware (not oblivious).
  • Funnel sort: a cache-oblivious sorting algorithm (recursively sorting N^(1/3) groups of N^(2/3) elements, merged with a K-funnel) that matches multiway merge sort's optimal cache complexity without tuning any parameter to the machine.

Walkthrough

The heat equation and stencil computation (1:01)

The lecture derives the finite-difference approximation of the 1D heat equation, showing that each new value depends on three neighboring values at the previous time step (a three-point stencil), and demonstrates that a straightforward row-by-row loop needs only two rows of storage but performs poorly in cache once a row exceeds the cache size, since each new row re-evicts the previous one.

The trapezoidal cache-oblivious algorithm (22:31)

The lecture defines trapezoidal regions in space-time whose points can be computed independently of anything outside the trapezoid, then gives the recursive rule: space-cut a too-wide trapezoid along a slope of -1 through its center (left half first, then right, since the right depends on the left); time-cut a too-tall trapezoid horizontally (bottom half first, then top). The base case is height one. A recursion-tree analysis shows this yields Theta(NT/(MB)) cache misses in 1D and generalizes to Theta(NT/(M^(1/D)*B)) in D dimensions, versus Theta(NT/B) for the naive loop.

Live demos and the prefetching surprise (34:39)

A simulated cache trace shows the trapezoidal code finishing with far fewer misses than the looping code. A real-time 2D heat-diffusion demo, however, shows only a modest speedup (about 1450 to 1830 iterations per second), which the lecture attributes to hardware prefetching helping the looping code's regular access pattern in the single-core, memory-bandwidth-rich serial case.

Parallelizing the trapezoidal algorithm (46:58)

Reusing the earlier theorem bounding parallel cache misses by serial misses plus O(steals * M/B), the lecture introduces the parallel space cut (a "V" cut producing two independent trapezoids plus a dependent one) so the stencil computation can run in parallel. On a larger offline benchmark (3000x3000 grid, four cores), the parallel looping code gets only about a 2x speedup while the parallel trapezoidal code gets nearly linear (about 3.96x), because parallel execution creates memory-bandwidth contention that hurts prefetching-reliant looping code far more than the cache-efficient trapezoidal code.

Diagnosing speedup bottlenecks (55:06)

The lecture lists four causes of poor parallel speedup: insufficient parallelism, scheduling overhead, lack of memory bandwidth, and contention (locking or false/true sharing), and gives a practical way to test for bandwidth limits: run several identical copies of the serial program in parallel and see if they slow each other down.

Cache-efficient sorting (59:10)

Starting from ordinary two-way merging (Theta(N/B) cache misses) and merge sort (Theta((N/B) log(N/M)) misses), the lecture introduces multiway merging with a tournament tree, showing that setting the fan-in R = Theta(M/B) gives Theta((N log N)/(B log M)) cache misses, a large improvement over binary merge sort for large inputs, but this "voodoo parameter" R makes it cache-aware. Funnel sort, built from recursively structured K-funnels, matches this optimal bound while remaining cache-oblivious.

Before you watch

  • Review the previous lecture's ideal-cache model, tall-cache assumption, and cache-oblivious matrix multiplication.
  • Recall the recursion-tree method for solving work and cache-miss recurrences, and the master theorem.
  • Be comfortable with the parallel cache-miss theorem relating Q_P to Q_1 and the number of successful steals.

Check your understanding

  1. Why must the left trapezoid in a space cut be computed before the right one?
  2. How does the cache-miss bound for the D-dimensional trapezoidal algorithm change as D increases, and why?
  3. Why did the serial demo show only a modest speedup for the cache-oblivious code despite far fewer cache misses, while the parallel demo showed a much larger gap?
  4. What four categories of causes should you check, in order, when a parallel program isn't speeding up as expected?
  5. Why does setting the merge fan-in R = Theta(M/B) in multiway merge sort make it cache-aware rather than cache-oblivious, and how does funnel sort avoid this?

Vocabulary

cache-oblivious (adjective)
Describing an algorithm that runs efficiently on any cache size without knowing that size in advance.
A cache-oblivious algorithm needs no tuning for a specific machine.
stencil computation (noun)
An update rule that recomputes each grid point from a small fixed set of neighboring points.
The heat equation is simulated with a three-point stencil computation.
heat equation (noun)
A mathematical equation describing how heat spreads over time through a space.
The lecture simulates the heat equation on a 1D row of points.
finite-difference approximation (noun)
A way to estimate a mathematical equation by using small, discrete steps instead of continuous values.
The finite-difference approximation turns the heat equation into a simple update rule.
divide-and-conquer (noun)
A method that splits a problem into smaller parts, solves each part, and combines the results.
The trapezoidal decomposition uses divide-and-conquer to split space-time into smaller pieces.
trapezoidal decomposition (noun)
A way of splitting a space-time region into trapezoid shapes so each part fits in cache.
Trapezoidal decomposition lets the stencil algorithm avoid extra cache misses.
recursion (noun)
A technique where a function solves a problem by calling itself on smaller versions of it.
The trapezoidal algorithm uses recursion until each piece is small enough.
base case (noun)
The simplest version of a problem where recursion stops and a direct answer is given.
The base case of the trapezoid recursion is a region of height one.
cache miss (noun)
An event where the computer cannot find needed data in fast cache memory and must fetch it from slower memory.
The naive loop causes many more cache misses than the trapezoidal method.
prefetching (noun)
A hardware technique that loads data into cache before it is actually needed, guessing what will be used next.
Hardware prefetching hides much of the memory delay in the looping code.
memory bandwidth (noun)
The amount of data that can move between memory and the processor in a given time.
Running many cores at once can use up all the available memory bandwidth.
contention (noun)
A situation where multiple processes compete for the same limited resource.
Memory bandwidth contention slows down the parallel looping code more than the cache-efficient code.
span (noun)
The length of the longest chain of dependent steps in a parallel computation.
Work and span together explain how much a program can speed up in parallel.
scheduler (noun)
The part of a system that decides which piece of work runs on which processor and when.
Scheduler overhead is one possible reason a parallel program runs slower than expected.
bottleneck (noun)
The part of a system that limits its overall speed or performance.
The checklist helps you find the bottleneck stopping a parallel program from speeding up.
false sharing (noun)
A performance problem where separate variables on the same cache line are wrongly treated as shared, slowing things down.
False sharing can quietly hurt performance even without any real data conflict.
diagnose (verb)
To find the cause of a problem by careful examination.
The lecture explains how to diagnose why a parallel program isn't speeding up.
merge sort (noun)
A sorting method that splits data into halves, sorts each half, and merges the sorted halves together.
Two-way merge sort combines two sorted lists into one.
multiway merge sort (noun)
A sorting method that merges many sorted sub-arrays together at once, instead of just two.
Multiway merge sort uses a tournament tree to combine several lists at once.
tournament tree (noun)
A tree structure used to repeatedly find the smallest remaining item among several lists.
The tournament tree picks the next smallest element during multiway merging.
fan-in (noun)
The number of inputs combined together at one step of a process.
Choosing the right fan-in for the merge affects how many cache misses occur.
cache-aware (adjective)
Describing an algorithm that is specially tuned using knowledge of the exact cache size.
Multiway merge sort is cache-aware because it needs a tuned parameter.
funnel sort (noun)
A cache-oblivious sorting algorithm that merges data using a recursively built structure called a K-funnel.
Funnel sort reaches the same speed as multiway merge sort without any tuning.
speedup (noun)
How much faster a program runs compared to a baseline version.
The parallel trapezoidal code achieves a speedup close to the number of cores.
linear (speedup) (adjective)
Describing a speedup that grows in direct proportion to the number of processors added.
Near-linear speedup means doubling the cores nearly doubles the speed.

Chapters

From the YouTube description

MIT 6.172 Performance Engineering of Software Systems, Fall 2018
Instructor: Julian Shun
View the complete course: https://ocw.mit.edu/6-172F18
YouTube Playlist: https://www.youtube.com/playlist?list=PLUl4u3cNGP63VIBQVWguXxZZi0566y7Wf

Prof. Shun discusses cache-oblivious algorithms through a simulation of heat diffusion and a 3-point stencil simulation. Caching and parallelism is discussed in Cillk.

License: Creative Commons BY-NC-SA
More information at https://ocw.mit.edu/terms
More courses at https://ocw.mit.edu

← 14. Caching and Cache-Efficient Algorithms · 16. Nondeterministic Parallel Programming →