This guide explains how this library calculates analytical MFU (Model FLOPs Utilization) predictions for distributed training with 3D parallelism.
- Overview
- Core MFU Formula
- Component Breakdown
- Overhead Factors
- Validation Methodology
- Troubleshooting
The MFU calculation models the entire training iteration, accounting for:
- Compute time: GEMM operations, attention, norms, activations
- Communication time: TP, DP, PP, EP collectives
- Overlap effects: DP communication overlapping with compute
- Pipeline bubbles: Fill/drain phases and steady-state inefficiency
- Launch overhead: CUDA kernel launch latency
Key principle: All models are physics-based or algorithm-based. No arbitrary multipliers.
MFU = (Model FLOPs per iteration) / (Peak Device FLOPs × Iteration Time)
where:
Model FLOPs = Forward + Backward compute (attention + MLP GEMMs)
Peak Device FLOPs = Hardware peak (e.g., 989 TFLOPS BF16 for H100)
Iteration Time = Compute + Communication + Bubbles + Overhead
Each transformer block consists of:
Pre Attn Norm: LayerNorm timing from lookup table (norm_rope_util.py)
RoPE: Rotary Position Embedding from lookup table
Pre Attn AG: TP All-Gather for Q, K, V projections
QKV Proj: GEMM [batch*seq, hidden] @ [hidden, 3*hidden]
SDPA: Scaled Dot-Product Attention (FlashAttention timing)
Attn Out Proj: GEMM [batch*seq, hidden] @ [hidden, hidden]
Post Attn RS: TP Reduce-Scatter after attention
Post Attn Residual: Residual addition (memory-bound)
Pre MLP Norm: LayerNorm timing from lookup table
Pre MLP AG: TP All-Gather for MLP input
MLP Up Proj: GEMM [batch*seq, hidden] @ [hidden, ffn_hidden]
MLP Down Proj: GEMM [batch*seq, ffn_hidden] @ [ffn_hidden, hidden]
Post MLP RS: TP Reduce-Scatter after MLP
Post MLP Residual: Residual addition
Router GEMM: [batch*seq, hidden] @ [hidden, n_experts]
Router TopK: TopK selection (k=2 typically)
Router Permutation: Token reordering for expert processing
Pre MLP A2A: All-to-All for expert parallelism
Expert GEMMs: Per-expert Up/Down projections
Post MLP A2A: All-to-All gather from experts
def compute_gemm_time_s(m: int, n: int, k: int, dtype: DType) -> float:
"""
GEMM: C[m,n] = A[m,k] @ B[k,n]
FLOPs = 2 * m * n * k (multiply-accumulate)
Utilization = lookup from gemm_util.parquet based on (m,n,k,device,dtype)
Time = FLOPs / (Peak FLOPs * Utilization)
"""Key insight: GEMM utilization varies significantly with problem size. Small GEMMs (e.g., router) may achieve only 30-40% of peak, while large GEMMs can reach 90%+.
Communication follows ring algorithm for TP/DP collectives:
Ring All-Gather time = Latency × (N-1) + BW × (N-1)/N
where:
Latency = hop latency × protocol multiplier
BW = (message_size / bandwidth) × protocol efficiency
N = degree of parallelism
Protocol selection (NCCL):
- LL (Low Latency): <32KB, 50% BW efficiency, 2.0× latency
- LL128: 32KB-1MB, 70% BW efficiency, 1.5× latency
- Simple: >1MB, 90% BW efficiency, 1.0× latency
Chunking overhead: Messages >512KB are chunked, adding ~2μs per additional chunk.
def calculate_dp_overlap_efficiency(
microbatch_compute_time: float,
comm_time_per_bucket: float,
n_buckets: int,
is_first_pp_stage: bool
) -> float:
"""
Physics: DP communication can only overlap during compute windows.
First PP stage: 0% overlap (no backward compute to overlap with)
Other stages: min(comm_time, compute_time) overlaps
"""Impact: First pipeline stage can see 2-4% lower MFU due to exposed DP time.
def calculate_kernel_launch_overhead(
n_layers: int,
kernels_per_block: int,
device: str
) -> float:
"""
Launch latency per kernel:
A100: ~8μs
H100/B200: ~5μs
Total overhead = (2 × n_layers × kernels_per_block) × launch_latency
Factor of 2 accounts for forward + backward passes
"""Impact: For 80-layer model with TP, ~12ms overhead (~1-2% of iteration time).
def calculate_pipeline_bubble(
pp: int,
vpp: int,
n_microbatches: int
) -> float:
"""
Three phases:
1. Fill: First (PP-1) microbatches fill pipeline
2. Steady-state: 1F1B scheduling with bubble = (PP-1)/(VPP * n_microbatches)
3. Drain: Last (PP-1) microbatches drain pipeline
Fill/drain phases have higher bubble: (PP-1)/PP
VPP only reduces steady-state bubble, not fill/drain
"""Impact: Most significant for small microbatch counts. For PP=4, n=2048: ~0.37% bubble.
Lookup tables replace rough HBM approximation:
Old approximation: 2 × data_size / memory_bandwidth
New lookup: empirical_time(batch, seqlen, hidden_dim, dtype, device)
Typical improvement:
LayerNorm: ~35% more accurate
RoPE: ~45% more accurate
Fallback to bandwidth estimation when lookup unavailable.
-
MLFlow Metrics: Real training job MFU via
mlflow_collector.py- Experiment IDs with diverse configurations
- Metrics: MFU, batch_time, samples/sec, load_balancing_loss
-
GPU Traces: Profiling data via
profile_parse/tools- CUDA kernel timing breakdown
- Communication operation timing
- Overlap efficiency measurements
-
Benchmark Data: Empirical lookup tables
benchmarks/results/gemm_util.parquet: GEMM utilization curves (H100/B200)benchmarks/results/sdpa.parquet: FlashAttention timing (8000+ measurements)norm_rope_timings.parquet: LayerNorm/RoPE timing
MAPE = (1/n) × Σ |predicted_mfu - actual_mfu| / actual_mfu × 100%
MAE = (1/n) × Σ |predicted_mfu - actual_mfu|
RMSE = sqrt((1/n) × Σ (predicted_mfu - actual_mfu)²)Baseline: 5-15% MAPE before improvements Target: <5% MAPE (stretch: <3%)
# Run full validation suite
python validation/run_regression_tests.py
# Generate error report
python validation/generate_error_report.py --output report.htmlError analysis breakdown by:
- PP degree (1, 2, 4, 8)
- DP degree (1, 2, 4, 8, 16)
- TP degree (1, 2, 4, 8)
- EP degree (1, 2, 4, 8)
- Model size and dtype
Symptom: Analytical MFU > Actual MFU by >10%
Possible causes:
-
Framework overhead not modeled
- CPU bottlenecks (data loading, preprocessing)
- Python GIL contention
- Synchronization overhead
Solution: Check CPU utilization and profiling traces
-
Communication overhead underestimated
- Network congestion or stragglers
- Suboptimal routing or topology
Solution: Validate actual comm times against model predictions
-
Memory bandwidth saturation
- Memory-bound operations slower than expected
- Memory fragmentation
Solution: Compare actual HBM bandwidth vs. peak
-
Insufficient microbatch count
- Pipeline bubble larger than modeled
- Fill/drain phases dominating
Solution: Increase global batch size or reduce microbatch size
Symptom: Analytical MFU < Actual MFU
Possible causes:
-
Compiler optimizations not modeled
- Kernel fusion reducing operations
- Memory access optimizations
Solution: This is rare but acceptable (conservative estimate)
-
Communication overlapped more than modeled
- Framework-specific optimizations
- Better overlap scheduling
Solution: Profile to verify overlap efficiency
High DP, Low PP configurations:
- Check DP overlap efficiency
- Verify first pipeline stage exposure
MoE configurations:
- Validate router operation timing
- Check load balancing metrics
- Verify expert parallelism communication
Small microbatch counts:
- Validate pipeline bubble calculation
- Check fill/drain phase impact
FP8 training:
- Ensure FP8 GEMM utilization data available
- Check mixed-precision overhead
dlcalc/training_3d.py: Main MFU calculation logicdlcalc/utils/comms.py: Communication modelingdlcalc/utils/gemm_util.py: GEMM utilization lookupsdlcalc/utils/norm_rope_util.py: Norm/RoPE timing lookupsdlcalc/utils/kernel_launch.py: Launch overhead modelingdlcalc/utils/overlap.py: DP overlap efficiencydlcalc/utils/moe_router_util.py: MoE router operations
- Ring algorithm: NCCL source code and documentation
- Pipeline parallelism: Megatron-LM paper, GPipe paper
- 1F1B scheduling: PipeDream paper
- NCCL protocols: NVIDIA/nccl#281
validation/mfu_error_tracker.py: Error calculation and trackingvalidation/mlflow_collector.py: MLFlow metrics collectionprofile_parse/: GPU trace parsing utilities
See CHANGELOG.md for detailed version history and improvement tracking.
February 2026: Major accuracy improvements
- Added DP overlap efficiency modeling (Task 1)
- Added NCCL protocol overhead modeling (Task 2)
- Added kernel launch overhead modeling (Task 3)
- Added Norm/RoPE empirical timing (Task 4)
- Added MoE router operation timing (Task 5)
- Added pipeline fill/drain phases (Task 6)
All improvements validated against real training jobs and GPU profiling data.