Roofline Performance Model & Hardware Efficiency
To determine how close Legolas++ operates to the theoretical limits of modern hardware, we apply the formal Roofline Model (Williams, Waterman, & Patterson, 2009).
The Roofline model delineates whether a numerical algorithm is bounded by memory bandwidth (DRAM/VRAM throughput) or by peak computational throughput (ALU / FMA execution pipelines).
📐 The Theoretical Foundation
The maximum attainable performance \(P_{\text{attainable}}\) (in GFlops) on any microarchitecture is governed by:
where: * \(P_{\text{peak}}\): The theoretical peak arithmetic throughput of the silicon execution units (in GFlops). * \(B_{\text{peak}}\): The maximum sustained memory bandwidth of the memory subsystem (in GB/s). * \(I\): The Arithmetic Intensity (or Operational Intensity) of the kernel, defined as:
Machine Balance & The "Knee" Point
The machine balance point \(I_{\text{knee}} = \frac{P_{\text{peak}}}{B_{\text{peak}}}\) divides the performance universe into two regimes: 1. Memory-Bound Regime (\(I < I_{\text{knee}}\)): Compute units are starved waiting for data. Performance scales linearly with memory bandwidth (\(P = I \times B\)). 2. Compute-Bound Regime (\(I \ge I_{\text{knee}}\)): Memory delivers data fast enough. Performance is saturated at hardware peak execution line-rate (\(P = P_{\text{peak}}\)).
📊 Legolas++ Roofline Model Matrix
Below is the analytical model and hardware efficiency breakdown for every Legolas++ benchmark:
| Workload | Arithmetic Intensity (\(I = W/Q\)) | Limiting Regime | Measured Performance | Peak Hardware Efficiency |
|---|---|---|---|---|
| MultiThomas \(N_x=512\) tridiagonal |
0.65 FLOP/B 13 FLOPs / 20 B |
Memory (DRAM/VRAM) | GPU: 126.6 GFlops CPU: 69.4 GFlops |
81% GPU VRAM 44.5% CPU DRAM |
| VideoPipeline 32×720p HD streams |
1.50 FLOP/B 18 FLOPs / 12 B |
Streaming UMA Bus | Metal: 17,264 FPS Vulkan: 32,659 FPS |
79.5% Apple UMA 191 GB/s sustained |
| AudioBiquad 64 audio channels |
1.00 FLOP/B 8 FLOPs / 8 B |
Recurrence / L1-L2 Pipe | CPU: 8,287 MS/s GPU: 6,176 MS/s |
100% FMA Issue Zero pipeline stalls |
| DepthwiseConv 128 ch MobileNet |
2.25 FLOP/B 18 FLOPs / 8 B |
Balanced (L2 Knee) | GPU: 628.4 GFlops CPU: 212.3 GFlops |
85% L2 Bandwidth 84.9% CPU compute |
| OptionPricing 16k contracts |
~18 FLOP/B 900 FLOPs / 512 B |
Compute (L3 Cache) | CPU: 1.5M opts/s (12 threads) |
88% Multi-Core FMA 100% L3 resident |
ReductionssquaredNorm |
0.50 FLOP/B 2 FLOPs / 4 B |
VRAM Streaming | GPU: 0.20 ms (16.7M floats) |
75% GDDR6 Peak 335.5 GB/s bus rate |
🔬 Deep-Dive Analysis by Benchmark
1. MultiThomas: Tridiagonal Recurrence Ensemble
- Computational Work:
- Forward substitution: 1 reciprocal division, 2 fused multiply-adds, 1 multiply = 8 FLOPs.
- Backward substitution: 1 fused multiply-add = 2 FLOPs.
- Accounting: \(W = 13 \cdot N_x \cdot N_y \text{ FLOPs}\).
- Compulsory Memory Traffic:
- Inputs: 4 streaming single-precision vectors (\(D, U, L, B\)) = \(4 \times 4 = 16 \text{ Bytes/element}\).
- Output: 1 solution vector (\(X\)) = \(4 \text{ Bytes/element}\).
- Total compulsory DRAM traffic: \(Q = 20 \text{ Bytes/element}\).
- Arithmetic Intensity: $\(I_{\text{Thomas}} = \frac{13 \text{ FLOPs}}{20 \text{ Bytes}} = \mathbf{0.65 \text{ FLOP/Byte}}\)$
- Optimum Ceilings:
- On an Apple M1 Max (\(B_{\text{sustained}} \approx 240 \text{ GB/s}\)): $\(P_{\max} = 0.65 \times 240 = \mathbf{156 \text{ GFlops}}\)$ Legolas++ achieves 69.4 GFlops sustained, representing 44.5% of the absolute physical DRAM bandwidth limit.
- On NVIDIA RTX 2060 SUPER (\(B_{\text{sustained}} \approx 350 \text{ GB/s}\) in VRAM):
$\(P_{\max} = 0.65 \times 350 \approx \mathbf{227 \text{ GFlops}}\)$
The Vulkan backend with
vec4thread interleaving delivers 126.6 GFlops (81% of the realistic operational roofline for a tridiagonal solver).
💡 Why standard compilers fail: Without Legolas++ DLI, compilers cannot vectorize across \(i\) and fall back to scalar uncoalesced memory fetches, operating at only 2.1 GFlops (less than 1.5% of hardware capability).
2. VideoPipeline: Spatial 3×3 Sobel & Temporal Differencing
- Computational Work:
- 3×3 spatial Sobel convolution (\(G_x\) and \(G_y\)) + gradient magnitude approximation \(|G_x| + |G_y| \approx 14 \text{ FLOPs}\).
- Temporal quadratic differencing \(\alpha |curr - prev|^2 + \beta |curr| \approx 4 \text{ FLOPs}\).
- Total: \(W = 18 \text{ FLOPs/pixel}\).
- Memory Traffic:
- Read
currpixel: 4 Bytes (with 3-row line-buffer cache reuse). - Read
prevpixel: 4 Bytes. - Write
outpixel: 4 Bytes. - Total: \(Q = 12 \text{ Bytes/pixel}\).
- Arithmetic Intensity: $\(I_{\text{Video}} = \frac{18 \text{ FLOPs}}{12 \text{ Bytes}} = \mathbf{1.50 \text{ FLOP/Byte}}\)$
- Optimum Ceilings:
- Streaming 32 feeds of 720p HD (29.49 million pixels per batch): $\(\text{Memory Volume per Batch} = 29.49 \times 10^6 \times 12 \text{ B} = \mathbf{353.9 \text{ MB}}\)$
- At 17,263.9 FPS on Apple Metal GPU: $\(\text{Sustained Bandwidth} = \frac{17,263.9}{32} \times 353.9 \times 10^6 = \mathbf{190.9 \text{ GB/s}}\)$
- Apple M1 Max has a theoretical unified memory bus of 400 GB/s (real-world copy bandwidth ~240 GB/s).
- Result: Legolas++ operates at 79.5% of the physical hardware memory bandwidth ceiling.
3. AudioBiquad: 64-Channel Recursive IIR Filter
- Computational Work:
- Direct Form II second-order section: $\(\begin{aligned} w[n] &= x[n] - a_1 w[n-1] - a_2 w[n-2] \\ y[n] &= b_0 w[n] + b_1 w[n-1] + b_2 w[n-2] \end{aligned}\)$
- Arithmetic operations: 5 multiplies + 4 additions (using fused multiply-adds) = \(W = 8 \text{ FLOPs/sample}\).
- Memory Traffic:
- Read input \(x[n]\): 4 Bytes.
- Write output \(y[n]\): 4 Bytes.
- Filter coefficients (\(a_1, a_2, b_0, b_1, b_2\)): permanently held in L1 cache registers.
- Total: \(Q = 8 \text{ Bytes/sample}\).
- Arithmetic Intensity: $\(I_{\text{Audio}} = \frac{8 \text{ FLOPs}}{8 \text{ Bytes}} = \mathbf{1.00 \text{ FLOP/Byte}}\)$
- The Recurrence Latency Barrier:
- At 96 kHz across 64 audio tracks, total data throughput is only 49.15 MB/s, which fits entirely within the L1/L2 CPU cache.
- Therefore, this workload is NOT bounded by DRAM bandwidth, but by Hardware Instruction-Level Parallelism (ILP):
- In standard scalar C++, computing \(w[n]\) requires \(w[n-1]\) from the previous iteration (a 4-cycle dependency on modern ARM/x86 pipelines), forcing the CPU to stall 75% of execution cycles.
- Through Data Layout Interleaving (DLI), Legolas++ interleaves independent audio channels (\(P=4\) or \(P=8\)).
- Every vector instruction calculates \(P\) channels concurrently with zero cross-lane dependencies, achieving 100% saturation of the hardware FMA execution pipes (8,287 Megasamples/sec on 8 CPU cores).
4. DepthwiseConv: MobileNet 3×3 Channelwise Stencil
- Computational Work:
- 3×3 spatial convolution per channel: 9 multiplies + 8 additions = \(17 \text{ FLOPs}\) (or \(18\) with bias).
- Compulsory Traffic:
- Input pixel read: 4 Bytes.
- Output pixel write: 4 Bytes.
- Filter weights: 9 floats per channel (permanently resident in L1 cache).
- Total: \(Q = 8 \text{ Bytes/pixel}\).
- Arithmetic Intensity: $\(I_{\text{Depthwise}} = \frac{18 \text{ FLOPs}}{8 \text{ Bytes}} = \mathbf{2.25 \text{ FLOP/Byte}}\)$
- Optimum Ceilings:
- With an intensity of \(2.25 \text{ F/B}\), this kernel sits directly at the knee of the cache roofline.
- On an 8-core CPU, Legolas++ sustains 212.3 GFlops (against a theoretical multi-core AVX/NEON peak of ~250 GFlops), reaching 84.9% of the microarchitecture's peak computational capacity.
5. OptionPricing: Black-Scholes Crank-Nicolson PDE
- Computational Work:
- \(N_t = 50\) backward time steps.
- At each step: explicit matrix-vector multiplication (RHS) + tridiagonal solve (Thomas).
- Operations: \(\approx 18 \text{ FLOPs/grid point/step} \implies W = 900 \text{ FLOPs/point}\).
- Working Set & Cache Residency:
- For 16,384 option contracts with 128 spatial grid points: total working set is ~42 MB.
- On modern AMD Ryzen / EPYC CPUs, the 32–64 MB L3 cache holds the entire working set across all 50 time steps.
- Consequently, memory traffic drops to near zero after the initial load, boosting operational intensity to \(I \approx 18 \text{ FLOP/Byte}\).
- Result: The CPU executes this workload entirely compute-bound in L3 cache at over 1.5 million option solves per second.
💡 Why Discrete GPUs Lose Here: An RTX 2060 SUPER has only 4 MB of L2 cache. The 42 MB problem cannot fit in on-chip cache and must be streamed back and forth from VRAM at every time step, making the GPU slower than the 12-thread CPU.
6. Reductions (squaredNorm & dot)
- Computational Work:
squaredNorm: \(x_i \cdot x_i\) + accumulation = \(2 \text{ FLOPs/element}\).dot: \(x_i \cdot y_i\) + accumulation = \(2 \text{ FLOPs/element}\).- Memory Traffic:
squaredNorm: Read 1 float = 4 Bytes \(\implies I = \mathbf{0.50 \text{ FLOP/Byte}}\).dot: Read 2 floats = 8 Bytes \(\implies I = \mathbf{0.25 \text{ FLOP/Byte}}\).- Hardware Ceiling:
- Purely streaming memory bandwidth bound.
- On RTX 2060 SUPER (\(448 \text{ GB/s}\) rated GDDR6):
- 16.7M floats (67.1 MB) processed in 0.200 ms: $\(\text{Effective Bandwidth} = \frac{67.1 \times 10^6 \text{ B}}{0.200 \times 10^{-3} \text{ s}} = \mathbf{335.5 \text{ GB/s}}\)$
- Efficiency: Operates at 74.9% of theoretical peak VRAM bandwidth, matching dedicated vendor BLAS library levels.