Purpose
This is the compact reference for the roofline analysis developed in Performance Modeling and applied in Optimizing GPU Kernels.
“When we run algorithms on hardware, we’re bounded by three things: how fast it can do math (OPs/second), the bandwidth available for moving data around (bytes/second), and the total memory available to store data (bytes). These “roofline” constraints let us upper and lower bound the time of a given computation.” - How to Scale Your Model - All About Rooflines
Arithmetic intensity
Definition: the arithmetic intensity of an algorithm is given by the ratio of the total FLOPs it performs to the number of bytes it needs to communicate, either within a chip or between chips.
We want models to run as compute-bound as possible, meaning the algorithm’s intensity meets or exceeds what the hardware supplies. That drives utilization up. A memory-bound workload leaves compute supply unmatched and the hardware underutilized.
Example: dot product
For in a 2-byte dtype (float16), we load elements ( bytes), write one ( bytes), and perform multiplications plus additions:
That is bad. An H100 supplies roughly 333 FLOPs per byte (see below), so the dot product is deeply memory bound and the GPU spends most of its time waiting on loads.
Roofline plot

Roofline plots put arithmetic intensity on the x-axis and performance on the y-axis, both usually log scale. Three regions matter:
- Roofline: the performance upper bound at each intensity, set by memory bandwidth on the left and peak compute on the right.
- Compute-bound: the flat region. Where compute-heavy workloads want to live.
- Memory-bound: the slanted region, where bandwidth caps performance.
Moving up within the memory-bound region means better data movement (coalesced access, tiling, faster memory) or better math throughput (multithreading, SIMD) once compute binds. NUMA effects make the memory side harder: when memory is “local” or “remote” relative to a core, careless placement turns into communication overhead.
Writing for operational intensity, a workload is compute bound when and memory bound when the inequality flips. The balance point is the critical operational intensity, . For an H100 at ~1000 FP16 TFLOPs and ~3 TB/s, the critical intensity is about 333 FLOPs/byte, so the dot product’s is very memory bound.
Matrix multiplication with FP16
For , , and : reads are bytes, writes bytes, compute FLOPs.
So with as the batch dimension, matmul goes compute bound on the H100 once .
Key hardware specs for serving throughput
- : number of GPUs
- : memory bandwidth (GB/s)
- : GPU interconnect bandwidth (GB/s)
- : GPU memory (GB)
- : GPU compute (TFLOPs)
Key model specs for serving throughput
- : hidden dimension size (
hidden_dim) - : number of layers (
num_layers) - : number of parameters
- : group size of GQA (
group_size) - : datatype size (
float16= 2 bytes,bfloat16= 2 bytes,int8= 1 byte) - : average number of tokens to prefill
- : average number of tokens to decode
- : average number of tokens per user request
- : per-request throughput
- : decoding throughput
Execution time model
Assume optimal batching and enough demand to keep the hardware fed.
Memory: each iteration effectively streams all of GPU memory (weights, activations, KV cache) once, so .
Compute: dense operations cost 2 FLOPs per parameter per batched token, so .
Network: for a model sharded across GPUs, the collectives that matter are AllGather and AllReduce.
AllGather: collect each GPU’s output; roughly network hops, with several per layer (4 in Llama 2).AllReduce: roughly twice the cost of anAllGather.