The Roofline Model

A scientist runs a matrix multiply on a new GPU and gets 40% of peak FLOP/s. She runs a stencil update and gets 4%. Same chip, wildly different outcomes. Why does one kernel sail near the hardware's advertised performance? Why does another crawl, no matter how much the code is tuned? The Roofline Model answers this with a single picture. Attainable performance is bounded by the smaller of two things. One is the chip's peak compute throughput. The other is the rate at which it can feed data from memory. This question sits at the center of performance engineering. It matters in every domain that touches high-performance computing. That includes deep learning training, scientific simulation, databases, video codecs, and warehouse-scale services. Modern processors have compute throughput that has grown far faster than memory bandwidth. This gap has widened over the past two decades. It is known as the memory wall. A kernel's performance is rarely limited by raw arithmetic capability alone. It is limited by whether the arithmetic units can be kept fed with operands. Understanding this tradeoff matters a great deal. It is the difference between believing "my code is slow, I need a faster chip." The correct diagnosis instead might be "my code is bandwidth-bound, a faster chip won't help." The Roofline Model was introduced by Samuel Williams, Andrew Waterman, and David Patterson. It gives this diagnosis a rigorous, visual, and quantitative form. It plots achievable performance (in FLOP/s) against a single derived quantity. That quantity is called arithmetic intensity. It is the ratio of operations performed to bytes moved from memory. The result is a log-log graph with two "roofs." One is a flat ceiling set by peak compute throughput. The other is a slanted ceiling set by peak memory bandwidth. Every kernel lands at a specific point under this roof, once you measure its arithmetic intensity. That point tells you exactly what to optimize next. This article builds the model from first principles. It covers how peak compute and peak bandwidth are measured. It shows how arithmetic intensity is computed from real code. It explains why the roofline shape is mathematically inevitable. It also shows how to read the diagram to make concrete engineering decisions. It closes by connecting the model to the large-scale performance reasoning used in Warehouse-Scale Computing. There, the same bound-and-bottleneck logic operates at the level of entire data centers.

Key takeaways
  • The Roofline Model bounds achievable performance by the minimum of peak compute throughput and peak-bandwidth-times-arithmetic-intensity.
  • Arithmetic intensity (AI) is operations per byte moved from memory: AI = FLOPs / Bytes.
  • On a log-log plot, the bound is a flat "compute roof" and a rising "memory roof," meeting at the ridge point.
  • Kernels left of the ridge point are memory-bound; kernels right of it are compute-bound.
  • The model is a hard upper bound derived from hardware limits, not a performance prediction — real performance sits at or below the roofline.
  • It directly guides optimization: increase AI (cache reuse, fusion) to escape the memory roof, or increase utilization (vectorization, ILP) to approach the compute roof.
The core insight

Attainable performance is capped by min(Peak Compute, Peak Memory Bandwidth × Arithmetic Intensity), so a single ratio tells you whether to optimize for data movement or for raw arithmetic.

The idea

The Roofline Model is a bound, not a simulation. It asks: given a chip's two hard physical limits — how many floating-point operations per second its arithmetic units can retire, and how many bytes per second its memory system can supply — what is the best performance any kernel could possibly achieve? The answer depends on one property of the kernel itself: its arithmetic intensity (AI), defined as ``` AI = Total Floating-Point Operations / Total Bytes Moved from Memory ``` measured in FLOPs per byte. A kernel with high AI reuses each byte it loads many times (e.g., dense matrix multiply, where each element participates in many multiply-adds). A kernel with low AI touches memory once or twice per operation (e.g., a vector addition, or a sparse matrix-vector product with poor locality). Crucially, "bytes moved from memory" means traffic across the boundary of interest — typically DRAM traffic after cache effects, not the algorithm's naive data footprint. This makes AI a property of the actual memory traffic pattern on a given machine, not just the algorithm's asymptotic complexity. Given AI, the model asserts an upper bound on attainable performance PP (in FLOP/s):

P≤min⁡(Ppeak,  BWpeak×AI)P \le \min\big(P_{\text{peak}},\ \ BW_{\text{peak}} \times AI\big)

where PpeakP_{\text{peak}} is the chip's peak floating-point throughput and BWpeakBW_{\text{peak}} is its peak sustained memory bandwidth. The first term says you can never exceed the hardware's raw compute rate no matter how efficient your memory access is. The second term says: if the kernel is starved for data, its performance is capped by how fast bytes arrive, scaled by how many operations each byte buys you. This single inequality, plotted on log-log axes with AI on the x-axis and performance on the y-axis, produces the characteristic "roofline" shape — a horizontal line at height PpeakP_{\text{peak}}, and a line of slope 1 (in log-log space, since BW×AIBW \times AI is linear in AIAI) rising from the origin, with the two meeting at the ridge point AIridge=Ppeak/BWpeakAI_{\text{ridge}} = P_{\text{peak}} / BW_{\text{peak}}. A kernel is memory-bound if its AI is left of the ridge point: no matter how well-optimized its arithmetic is, it cannot rise above the slanted memory roof, and the only way to improve performance is to increase AI or increase effective bandwidth. A kernel is compute-bound if its AI is right of the ridge point: it has enough arithmetic work per byte that memory bandwidth is not the constraint, and the only way to improve performance is to increase compute utilization — better vectorization (GPUs and SIMD Execution), more instruction-level parallelism, or fewer wasted cycles. The model turns a vague complaint ("my kernel is slow") into a precise, falsifiable diagnostic question: which side of the ridge point am I on, and how far below my roof do I sit?

How it works

Building and using a roofline analysis proceeds in four stages: characterize the hardware, characterize the kernel, plot the two together, and interpret the gap between the measured point and the roof.

Stage 1 — Characterize the machine. Measure PpeakP_{\text{peak}} from the chip's specification (cores × clock × FLOPs/cycle per core, accounting for SIMD width and fused multiply-add) or empirically via a compute-saturating microbenchmark. Measure BWpeakBW_{\text{peak}} empirically using a bandwidth-saturating benchmark such as STREAM (large-array copy/scale/add/triad), since real sustained bandwidth is reliably lower than the theoretical pin bandwidth.

Stage 2 — Characterize the kernel. Instrument or model the kernel to obtain total floating-point operations FF and total bytes moved from the memory level of interest BB (often DRAM, but the model composes across cache levels too). Compute AI=F/BAI = F / B.

Stage 3 — Plot. On log-log axes (x = AI in FLOPs/byte, y = performance in FLOP/s), draw the flat compute roof at PpeakP_{\text{peak}} and the memory roof as the line y=BWpeak⋅xy = BW_{\text{peak}} \cdot x. Plot the kernel's measured performance at its measured AI.

Stage 4 — Interpret. If the point sits far below the roof directly above it, the gap is inefficiency — something other than the fundamental hardware limit is holding performance back (poor vectorization, cache conflicts, insufficient parallelism, load imbalance). If the point sits close to the roof, the kernel is near-optimal for its AI, and the only path to further speedup is changing the AI itself (algorithmic reuse) or upgrading hardware. ```

# ROOFLINE ANALYSIS — computing the bound and classifying a kernel function ROOFLINE_BOUND(P_peak, BW_peak, kernel): F <- count_flops(kernel) # total floating-point ops executed B <- count_bytes_moved(kernel) # total bytes crossing the memory

# boundary of interest (e.g. DRAM) AI <- F / B # arithmetic intensity, FLOPs/byte ridge <- P_peak / BW_peak # AI at which the two roofs meet bound <- min(P_peak, BW_peak * AI) # the attainable-performance ceiling if AI < ridge: regime <- "MEMORY-BOUND"

# bound is governed by the slanted roof: bound = BW_peak * AI else: regime <- "COMPUTE-BOUND"

# bound is governed by the flat roof: bound = P_peak measured <- F / measured_time(kernel) # actual achieved FLOP/s efficiency <- measured / bound # how close to the roof we are return (AI, bound, regime, measured, efficiency)

function OPTIMIZE_GUIDANCE(regime, efficiency, threshold=0.7): if efficiency >= threshold: if regime == "MEMORY-BOUND": return "Near roof: only fix is raise AI (blocking, fusion, reuse)" else: return "Near roof: only fix is faster hardware or lower precision" else: if regime == "MEMORY-BOUND": return "Below roof: fix memory access pattern, prefetch, alignment" else: return "Below roof: fix vectorization, ILP, branch/stall overhead" ``` The core plotting step — drawing min⁡(Ppeak,BWpeak⋅AI)\min(P_{\text{peak}}, BW_{\text{peak}} \cdot AI) as a function of AIAI — is exactly what produces the two-segment shape in the figure below. Real rooflines often add extra ceilings beneath the top ones (e.g., a lower roof for scalar, non-vectorized code, or a lower bandwidth roof for a slower cache level), turning the single-roof diagram into a stack of achievable ceilings that captures partial optimizations (vectorized-but-not-multithreaded, cache-resident-but-not-vectorized, etc.).

Figure
The Roofline: two ceilings meeting at the ridge point, with kernels plotted by arithmetic intensity
Arithmetic Intensity (FLOPs / byte) — log scale Performance (FLOP/s) — log scale memory roof: BW_peak × AI compute roof: P_peak ridge point (AI_ridge = P_peak / BW_peak) MEMORY-BOUND region COMPUTE-BOUND region STREAM triad (AI≈0.1, near roof) SpMV (AI≈0.25, below roof — irregular access) 7-pt stencil (AI≈1, near memory roof) Dense GEMM (AI large, near compute roof) Naive GEMM (same AI, poor cache blocking)

Complexity & correctness

The Roofline Model is not an algorithm with a running-time complexity in the usual sense; it is an analytic bound, so "complexity" here means the cost of computing the bound, and "correctness" means proving the inequality actually holds and characterizing when it is tight.

Cost of computing the roofline. Determining PpeakP_{\text{peak}} and BWpeakBW_{\text{peak}} requires O(1)O(1) microbenchmarks per machine (amortized across every kernel analyzed on it). Determining a kernel's AIAI requires counting FLOPs and bytes moved, which for a kernel with a known access pattern is a static, closed-form calculation — O(1)O(1) given the kernel's loop structure — or, for arbitrary code, an O(n)O(n) instrumentation pass over the nn dynamic instructions executed (hardware performance counters give this essentially for free at run time). So building a roofline plot for a kernel costs asymptotically nothing beyond running the kernel once with counters enabled.

Correctness of the bound. The inequality P≤min⁡(Ppeak,BWpeak⋅AI)P \le \min(P_{\text{peak}}, BW_{\text{peak}} \cdot AI) follows from two independent physical constraints, each individually tight: 1. Compute constraint. The chip can retire at most PpeakP_{\text{peak}} FLOP/s by definition of peak throughput (it is derived from the number of functional units, SIMD lanes, and clock rate). No sequence of instructions can exceed this, since it is the maximum issue-and-execute rate of the hardware. Hence P≤PpeakP \le P_{\text{peak}} always. 2. Bandwidth constraint. In time TT, the memory system can deliver at most BWpeak⋅TBW_{\text{peak}} \cdot T bytes. The kernel needs BB bytes total to do its FF operations, so it needs at least T≥B/BWpeakT \ge B / BW_{\text{peak}} seconds just to receive its data (assuming compute cannot get ahead of arriving data — true unless data is stale/reused without arriving anew, which is exactly what AI already accounts for). Therefore

P=FT≤FB/BWpeak=BWpeak⋅FB=BWpeak⋅AI.P = \frac{F}{T} \le \frac{F}{B / BW_{\text{peak}}} = BW_{\text{peak}} \cdot \frac{F}{B} = BW_{\text{peak}} \cdot AI.

Both constraints must hold simultaneously — the chip cannot compute faster than its ALUs allow, and it cannot compute faster than data arrives — so the true bound is the minimum of the two, and the roofline's min⁡(⋅,⋅)\min(\cdot,\cdot) shape is not a modeling choice but a direct consequence of two simultaneously-necessary conditions. This is why the roofline is called a bound: it is provably an upper limit, derived from physical resource limits, and any measured performance satisfies P≤roof(AI)P \le \text{roof}(AI) by construction. It says nothing by itself about whether that bound is achieved — achieving it requires perfect overlap of computation and communication, perfect utilization of all functional units, and zero stalls, which real code rarely attains perfectly.

Honesty about assumptions and tradeoffs.

  • The bound assumes compute and memory transfer can be fully overlapped (double-buffered/pipelined). If a kernel is instead alternately compute-then-wait-then-compute with no overlap, actual time is F/Ppeak+B/BWpeakF/P_{\text{peak}} + B/BW_{\text{peak}}, which is strictly worse than max⁡\max of the two terms and can be far worse than the roofline's min⁡\min-based bound — the classical roofline is an optimistic (best-case) bound, not a worst-case one.
  • AIAI is not a fixed property of an algorithm; it depends on the memory hierarchy level chosen as the boundary. A kernel might have low AI relative to DRAM but high AI relative to L1 cache, since a well-blocked algorithm reuses data heavily once it is resident on-chip. This is why "cache-aware" rooflines draw multiple memory roofs (one per cache level), each with its own bandwidth.
  • Peak bandwidth and peak compute are themselves idealized numbers; sustained bandwidth measured by STREAM is typically 60-90% of the theoretical pin bandwidth, and using the theoretical peak makes the roof optimistic (kernels may appear "more memory-bound" than they practically are). Careful roofline studies always use empirically measured ceilings.
  • The model captures only FLOPs and bytes; it says nothing about latency-bound kernels (e.g., pointer-chasing with poor prefetchability) where neither bandwidth nor compute is the bottleneck, but rather memory latency combined with insufficient concurrency to hide it. Extensions (e.g., adding a "concurrency roof" based on Little's Law) are needed for such cases.

Worked example

Consider a machine with

Ppeak=200 GFLOP/s,BWpeak=50 GB/sP_{\text{peak}} = 200\ \text{GFLOP/s}, \qquad BW_{\text{peak}} = 50\ \text{GB/s}

so the ridge point is AIridge=200/50=4AI_{\text{ridge}} = 200/50 = 4 FLOPs/byte. We analyze three kernels operating on double-precision (8-byte) arrays of size nn.

Kernel A — SAXPY-like vector update `y[i] = a*x[i] + y[i]` for i=0…n−1i = 0 \ldots n-1. Per iteration: 2 FLOPs (one multiply, one add). Memory traffic per iteration (assuming compulsory misses only, streaming access, write-allocate ignored for simplicity): read `x[i]` (8B), read `y[i]` (8B), write `y[i]` (8B) = 24 bytes.

AIA=224=0.083 FLOPs/byteAI_A = \frac{2}{24} = 0.083 \text{ FLOPs/byte}

This is far left of the ridge point (0.083 ≪ 4), so Kernel A is memory-bound. Its bound is

PA≤BWpeak×AIA=50×0.083=4.17 GFLOP/s.P_A \le BW_{\text{peak}} \times AI_A = 50 \times 0.083 = 4.17\ \text{GFLOP/s}.

Even a perfectly-vectorized, perfectly-pipelined implementation cannot exceed about 4.2 GFLOP/s on this machine — roughly 2% of the chip's peak compute rate. If a benchmark measures 3.9 GFLOP/s for this kernel, that is excellent (93% of its roof), even though it looks abysmal (2%) relative to peak FLOP/s. The naive metric "% of peak FLOPs" is the wrong way to judge this kernel; "% of its own roofline bound" is the right one.

Kernel B — Dense matrix multiply C=ABC = AB for n×nn \times n matrices, with a cache-blocked (tiled) implementation. Total FLOPs: 2n32n^3 (one multiply + one add per inner-product term). With good blocking, each matrix element is reused across a tile of size bb, and the DRAM traffic is approximately O(n3/b)O(n^3/b) instead of the naive O(n3)O(n^3) — this is the entire point of tiling. Suppose blocking achieves effective DRAM traffic of B≈4n3/bB \approx 4n^3/b bytes with a tile factor b=64b = 64 elements (a realistic cache-blocking factor):

AIB=2n3(4n3/64)=2×644=32 FLOPs/byteAI_B = \frac{2n^3}{(4n^3/64)} = \frac{2 \times 64}{4} = 32 \text{ FLOPs/byte}

This is right of the ridge point (32 > 4), so Kernel B is compute-bound. Its bound is simply

PB≤Ppeak=200 GFLOP/s.P_B \le P_{\text{peak}} = 200\ \text{GFLOP/s}.

A good blocked GEMM implementation should approach 200 GFLOP/s, limited now only by vectorization efficiency, instruction scheduling, and register blocking — not by memory traffic at all.

Kernel C — Naive (unblocked) matrix multiply, same 2n32n^3 FLOPs, but with poor locality: the inner loop repeatedly reloads rows/columns from DRAM because the working set does not fit in cache. Suppose this results in DRAM traffic close to O(n3)O(n^3) bytes (each of the n3n^3 inner-loop iterations effectively misses to DRAM), say B≈8n3B \approx 8n^3 bytes (reading two 8-byte operands per iteration with no reuse):

AIC=2n38n3=0.25 FLOPs/byteAI_C = \frac{2n^3}{8n^3} = 0.25 \text{ FLOPs/byte}

Despite doing identical arithmetic to Kernel B, Kernel C is now far left of the ridge point and memory-bound:

PC≤BWpeak×AIC=50×0.25=12.5 GFLOP/s.P_C \le BW_{\text{peak}} \times AI_C = 50 \times 0.25 = 12.5\ \text{GFLOP/s}.

This is the pedagogically crucial case: same algorithm, same FLOP count, same hardware — but a data-layout/blocking decision moves the kernel from a 200 GFLOP/s ceiling down to a 12.5 GFLOP/s ceiling, a 16× loss, purely from memory traffic. No amount of instruction-level tuning of Kernel C's inner loop can push it past 12.5 GFLOP/s; the fix must be algorithmic (blocking/tiling to raise AI), not micro-optimization.

KernelFLOPsBytesAI (FLOPs/byte)RegimeRoofline bound
A: SAXPY2n2n24n24n0.083memory-bound4.17 GFLOP/s
B: Blocked GEMM2n32n^34n3/644n^3/6432compute-bound200 GFLOP/s
C: Naive GEMM2n32n^38n38n^30.25memory-bound12.5 GFLOP/s

Common pitfalls & traps

PitfallWhy it happensConsequence / fix
Using theoretical peak bandwidth instead of measured (STREAM) bandwidthSpec sheets quote pin bandwidth, not sustained bandwidthRoofline looks more permissive than reality; always calibrate with a bandwidth microbenchmark
Counting algorithmic data footprint instead of actual DRAM trafficConflating "data touched" with "data moved across the boundary"AI is overestimated for kernels with poor cache reuse; measure traffic with hardware counters, not just array sizes
Judging all kernels by "% of peak FLOP/s"Ignoring that memory-bound kernels have a much lower personal ceilingMisleads engineers into "optimizing" code that is already at 95% of its true (memory) roof
Ignoring the ridge point when choosing what to optimizeApplying vectorization tricks to a memory-bound kernelWasted engineering effort — compute optimizations cannot move a point stuck under the memory roof
Treating the roofline as a guaranteed performance predictionThe model gives an upper bound, assuming perfect overlapReal code with poor compute/communication overlap can fall well below even the correct-regime roof
Forgetting multiple memory levels (only using DRAM bandwidth)Simplified single-roof diagrams omit cache-level roofsKernel appears memory-bound at DRAM when it is actually compute-bound relative to a faster on-chip cache

Pioneers & history

The Roofline Model was formalized in the mid-2000s at UC Berkeley as multicore and manycore chips made the compute/bandwidth gap acute and existing performance models too coarse to guide optimization. It built on decades of prior insight — most directly the recognition, going back to computer architecture's earliest performance equations, that memory access cost and compute cost are separate resources that must both be accounted for, an idea foundational to Performance Metrics and the CPU Time Equation.

Origins · 1 minDavid A. Patterson and how this was discovered
DA
David A. Patterson
born 1947 · Co-developer of the Roofline Model; co-author of RISC and RAID; central figure in quantitative computer architecture

David Patterson, alongside John Hennessy, established the discipline of quantitative computer architecture — measuring, modeling, and predicting performance from first principles rather than intuition. The Roofline Model, developed with Samuel Williams and Andrew Waterman, extended this quantitative tradition to the multicore era, giving engineers a visual tool to separate "the hardware's fault" from "the code's fault" when a kernel underperforms.

History
2004
— Berkeley researchers begin formalizing bandwidth-vs-compute bounds for emerging multicore processors.
2009
— Samuel Williams, Andrew Waterman, and David Patterson publish "Roofline: An Insightful Visual Performance Model for Multicore Architectures" in Communications of the ACM.
2010
s — The model is extended with cache-level rooflines, instruction-mix-aware ceilings, and empirical toolchains (e.g., Intel Advisor, ERT, LIKWID) for automated roofline generation.
2018
— Roofline analysis is adapted for GPU accelerators and later for specialized ML accelerators (TPUs), incorporating tensor-core and memory-hierarchy-specific ceilings.
2020
s — Hierarchical rooflines become standard in HPC performance engineering and are integrated into profiling tools used across scientific computing and machine learning training pipelines.

Where this matters

The Roofline Model is now a standard diagnostic in high-performance computing centers, where scientists profile simulation codes (climate models, molecular dynamics, computational fluid dynamics) to decide whether to invest engineering time in cache blocking, data layout changes, or instruction-level tuning. GPU and accelerator vendors publish roofline-style specifications explicitly, since GPUs and SIMD Execution hardware exposes an enormous compute-to-bandwidth ratio that makes the memory-bound/compute-bound distinction especially consequential — many deep learning training kernels (batch normalization, small matrix operations, attention with short sequences) are memory-bound and benefit far more from kernel fusion (raising AI by avoiding round-trips to DRAM) than from faster arithmetic units. Compiler and library authors (BLAS, cuDNN, oneDNN) design blocking strategies whose entire purpose is to push a kernel's operating point rightward past the ridge point. At data-center scale, the same reasoning about resource bottlenecks — is the system limited by compute, by memory bandwidth, by network bandwidth, or by storage I/O — recurs as the organizing question behind capacity planning and scheduling in Warehouse-Scale Computing, where the roofline's core lesson generalizes: identify the scarcest resource, and optimize toward it, not away from it.

Ask the tutor: How would the roofline diagram change if I plotted arithmetic intensity relative to on-chip cache bandwidth instead of DRAM bandwidth?

Is the Roofline Model a prediction of actual runtime, or just an upper bound?

It is strictly an upper bound, not a prediction. The model derives P≤min⁡(Ppeak,BWpeak⋅AI)P \le \min(P_{\text{peak}}, BW_{\text{peak}} \cdot AI) from two independent physical constraints that must both hold, so real measured performance can only sit at or below the roofline — never above it. Whether a real kernel actually reaches its roof depends on factors the basic model ignores: how well compute and memory transfer overlap, how efficiently the compiler vectorizes the inner loop, whether there is enough parallelism to hide memory latency, and whether cache conflicts or bank conflicts introduce stalls. A kernel can have an excellent arithmetic intensity and still perform far below its roof if the code is poorly scheduled. The roofline tells you the best case; profiling tells you how close you got, and the gap tells you what kind of optimization (if any) is still worth pursuing.

How do I actually measure the bytes moved for arithmetic intensity, since caching makes "bytes touched" different from "bytes transferred"?

The correct denominator is memory traffic actually crossing the boundary you care about — usually DRAM traffic, since that is where the true bandwidth bottleneck lives on most systems. This is best measured with hardware performance counters (e.g., counters for last-level cache misses times cache line size) rather than computed from the algorithm's naive footprint, because cache reuse can dramatically reduce real DRAM traffic below the total data touched by the algorithm. Tools like Intel VTune, Intel Advisor, LIKWID, or vendor profilers on GPUs expose these counters directly and can compute AI automatically. For a purely analytical estimate (as in the worked example), you model the access pattern and cache behavior explicitly, but this is an approximation; measured counters are the ground truth.

Can a kernel move between the memory-bound and compute-bound regimes just by changing the hardware it runs on?

Yes, and this is one of the model's most important lessons. Arithmetic intensity is a fixed property of the kernel's algorithm and implementation (for a fixed memory boundary), but the ridge point AIridge=Ppeak/BWpeakAI_{\text{ridge}} = P_{\text{peak}} / BW_{\text{peak}} is a property of the hardware. Because compute throughput has grown faster than memory bandwidth across processor generations, the ridge point has been drifting rightward over time — meaning a kernel that was comfortably compute-bound on an older chip can become memory-bound on a newer one with much higher peak FLOP/s but only modestly higher bandwidth. This is exactly the memory wall phenomenon, and it is why kernels that once scaled well with faster chips can stop scaling: the bottleneck silently shifted from compute to memory.

How does the Roofline Model relate to Amdahl's Law?

Both are bounding arguments about a system with heterogeneous resources, but they bound different things. Amdahl's Law bounds speedup from parallelizing a fraction of a program, given a fixed serial remainder; it reasons about the fraction of work that can be sped up. The Roofline Model bounds achievable throughput given two physical resource ceilings (compute and bandwidth) and a workload's intrinsic ratio (arithmetic intensity) between them. Where Amdahl's Law says "the sequential part will eventually dominate no matter how many processors you add," the Roofline Model says "memory traffic will eventually dominate no matter how many FLOP/s the chip can issue, unless the algorithm reuses data." Both are instances of the same engineering principle: identify the scarcest resource and reason about the system relative to it, a principle also central to analyzing performance in Warehouse-Scale Computing.

Does the Roofline Model apply to GPUs and specialized accelerators, or only CPUs?

It applies to any processor with well-defined peak compute throughput and peak memory bandwidth, which includes GPUs, TPUs, and other accelerators — arguably it is even more important there. GPUs (see GPUs and SIMD Execution) typically have an enormous ratio of compute to bandwidth compared to CPUs, pushing the ridge point far to the right; this means many workloads that look compute-heavy on paper (e.g., small batch matrix multiplications, many normalization and activation layers in deep learning) are actually memory-bound on GPUs. This is precisely why kernel fusion — combining several low-AI operations into one pass over data — is such a dominant optimization strategy in deep learning compilers and libraries: it raises effective arithmetic intensity by avoiding repeated round-trips to device memory.

What extensions exist beyond the basic two-roof model?

Several refinements address the basic model's simplifications. Hierarchical (or cache-aware) rooflines add one bandwidth roof per level of the memory hierarchy (L1, L2, L3, DRAM), each with its own AI computed relative to that level, capturing kernels that are compute-bound relative to fast cache but memory-bound relative to DRAM. Instruction-mix rooflines add ceilings below the top compute roof for partially-optimized code (scalar-only, no fused multiply-add, single-threaded), showing incremental progress toward peak. Some extensions add a latency- or concurrency-based ceiling derived from Little's Law, capturing kernels bottlenecked by insufficient outstanding memory requests rather than by bandwidth or compute directly — a case the classical model does not address at all.

If a kernel is memory-bound, is buying a faster CPU/GPU (with higher peak FLOP/s) ever worth it?

Only if the faster chip also brings proportionally more memory bandwidth, or if the kernel's arithmetic intensity can be raised to make use of the extra compute. A memory-bound kernel's roofline bound is BWpeak⋅AIBW_{\text{peak}} \cdot AI, which does not depend on PpeakP_{\text{peak}} at all — so upgrading to a chip with 3× the FLOP/s but the same bandwidth yields zero improvement for that kernel. This is a common and costly mistake in hardware procurement: buying compute-heavy accelerators for workloads that are actually bandwidth-starved. The roofline makes this failure mode visible before money is spent, by showing that the kernel's point is pinned under the (unchanged) memory roof regardless of how high the compute roof is raised.

Before this