Upload kb/rocm_rules.yaml with huggingface_hub
Browse files- kb/rocm_rules.yaml +468 -0
kb/rocm_rules.yaml
ADDED
|
@@ -0,0 +1,468 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# GPU Goblin — curated ROCm / MI300X optimization rules.
|
| 2 |
+
#
|
| 3 |
+
# Each entry is validated against agent.schemas.Rule at module import.
|
| 4 |
+
# Rules are hand-curated from ROCm docs + AMD blog posts. NO LLM-generated rules.
|
| 5 |
+
# This is the moat — every recommendation in the final report is grounded here.
|
| 6 |
+
#
|
| 7 |
+
# Ordering note: file order is irrelevant; query_rocm_kb.py ranks by cosine
|
| 8 |
+
# similarity between query symptom and rule.symptom embeddings.
|
| 9 |
+
|
| 10 |
+
# ---------------------------------------------------------------------------
|
| 11 |
+
# precision
|
| 12 |
+
# ---------------------------------------------------------------------------
|
| 13 |
+
|
| 14 |
+
- id: precision.bf16_over_fp16_on_mi300x
|
| 15 |
+
category: precision
|
| 16 |
+
targets_bucket: precision_path
|
| 17 |
+
symptom: >-
|
| 18 |
+
fp16 used on MI300X / CDNA3 matrix cores. Loss can NaN on long fine-tuning
|
| 19 |
+
runs and there is no throughput benefit over bf16 — the reflexive NVIDIA
|
| 20 |
+
default carries forward without thinking.
|
| 21 |
+
detect:
|
| 22 |
+
precision: fp16
|
| 23 |
+
transform:
|
| 24 |
+
precision: bf16
|
| 25 |
+
expected_recovery_fraction: 0.85
|
| 26 |
+
expected_impact: >-
|
| 27 |
+
MI300X CDNA3 matrix cores execute bf16 at the same throughput as fp16 with
|
| 28 |
+
strictly better numerical stability. Switch removes NaN risk in long runs;
|
| 29 |
+
no loss-scaling required.
|
| 30 |
+
rocm_version_min: "6.0"
|
| 31 |
+
citation: "ROCm MI300X Optimization Guide §3.2 — bf16 vs fp16"
|
| 32 |
+
|
| 33 |
+
- id: precision.fp32_default_wastes_matrix_cores
|
| 34 |
+
category: precision
|
| 35 |
+
targets_bucket: precision_path
|
| 36 |
+
symptom: >-
|
| 37 |
+
Training in fp32 on MI300X. The CDNA3 matrix cores deliver ~2x throughput
|
| 38 |
+
in bf16 vs fp32 and the LoRA fine-tuning loss surface tolerates bf16
|
| 39 |
+
cleanly — fp32 is simply leaving silicon idle.
|
| 40 |
+
detect:
|
| 41 |
+
precision: fp32
|
| 42 |
+
transform:
|
| 43 |
+
precision: bf16
|
| 44 |
+
expected_recovery_fraction: 0.6
|
| 45 |
+
expected_impact: >-
|
| 46 |
+
Switching fp32 → bf16 nets roughly 2x matmul throughput on MI300X and
|
| 47 |
+
halves activation memory, which usually unlocks a larger batch size as a
|
| 48 |
+
follow-on win.
|
| 49 |
+
rocm_version_min: "6.0"
|
| 50 |
+
citation: "AMD MI300X Tuning Guide — Matrix-core throughput by precision"
|
| 51 |
+
|
| 52 |
+
# ---------------------------------------------------------------------------
|
| 53 |
+
# attention
|
| 54 |
+
# ---------------------------------------------------------------------------
|
| 55 |
+
|
| 56 |
+
- id: attention.flash_rocm_over_eager
|
| 57 |
+
category: attention
|
| 58 |
+
targets_bucket: kernel_shape
|
| 59 |
+
symptom: >-
|
| 60 |
+
Naive (eager) attention on MI300X — no flash kernel loaded, attention
|
| 61 |
+
materializes the full O(seq_len^2) matrix. Most MI300X waste at long
|
| 62 |
+
context lives here.
|
| 63 |
+
detect:
|
| 64 |
+
attention_impl: eager
|
| 65 |
+
transform:
|
| 66 |
+
attention_impl: flash_rocm
|
| 67 |
+
expected_recovery_fraction: 0.7
|
| 68 |
+
expected_impact: >-
|
| 69 |
+
Use the ROCm-validated flash-attention kernel (Optimum-AMD ships a tested
|
| 70 |
+
build). Eliminates the O(seq_len^2) attention memory blow-up; typically
|
| 71 |
+
2-3x faster on MI300X for seq_len >= 1024.
|
| 72 |
+
rocm_version_min: "6.0"
|
| 73 |
+
citation: "AMD Optimum-AMD docs — Flash Attention 2 validated on MI300"
|
| 74 |
+
|
| 75 |
+
- id: attention.sdpa_over_eager
|
| 76 |
+
category: attention
|
| 77 |
+
targets_bucket: kernel_shape
|
| 78 |
+
symptom: >-
|
| 79 |
+
Eager attention used when a drop-in faster path exists. PyTorch SDPA on
|
| 80 |
+
ROCm dispatches to a fused kernel without requiring the flash-attn fork
|
| 81 |
+
install — the lowest-friction attention upgrade available.
|
| 82 |
+
detect:
|
| 83 |
+
attention_impl: eager
|
| 84 |
+
transform:
|
| 85 |
+
attention_impl: sdpa
|
| 86 |
+
expected_recovery_fraction: 0.45
|
| 87 |
+
expected_impact: >-
|
| 88 |
+
PyTorch's torch.nn.functional.scaled_dot_product_attention on ROCm is a
|
| 89 |
+
fused, memory-efficient backend with no extra dependency. Slower than
|
| 90 |
+
flash-attn ROCm but a one-line config change with no install pain.
|
| 91 |
+
rocm_version_min: "6.0"
|
| 92 |
+
citation: "PyTorch SDPA backend selection — ROCm support notes"
|
| 93 |
+
|
| 94 |
+
# ---------------------------------------------------------------------------
|
| 95 |
+
# memory
|
| 96 |
+
# ---------------------------------------------------------------------------
|
| 97 |
+
|
| 98 |
+
- id: memory.batch_too_small_for_192gb
|
| 99 |
+
category: memory
|
| 100 |
+
targets_bucket: memory_headroom
|
| 101 |
+
symptom: >-
|
| 102 |
+
HBM peak is far below MI300X's 192 GB ceiling — the user copied a batch
|
| 103 |
+
size from an A100 80GB tutorial and is leaving more than half the HBM
|
| 104 |
+
idle every step.
|
| 105 |
+
detect:
|
| 106 |
+
batch_size: {"$lt": 8}
|
| 107 |
+
transform:
|
| 108 |
+
batch_size: 12
|
| 109 |
+
expected_recovery_fraction: 0.55
|
| 110 |
+
expected_impact: >-
|
| 111 |
+
Raising batch size to fill more of the 192 GB HBM increases tokens/sec
|
| 112 |
+
proportionally for compute-bound LoRA workloads. Adjust grad-accum down
|
| 113 |
+
to keep effective batch unchanged if needed.
|
| 114 |
+
rocm_version_min: "6.0"
|
| 115 |
+
citation: "AMD Instinct MI300X — 192 GB HBM3 fine-tuning playbook"
|
| 116 |
+
|
| 117 |
+
- id: memory.gradient_checkpointing_for_long_seq
|
| 118 |
+
category: memory
|
| 119 |
+
targets_bucket: memory_headroom
|
| 120 |
+
symptom: >-
|
| 121 |
+
Long sequences (seq_len >= 4096) without gradient checkpointing are
|
| 122 |
+
spending HBM on activations that could be recomputed instead — leaving
|
| 123 |
+
no headroom to grow the batch.
|
| 124 |
+
detect:
|
| 125 |
+
seq_len: {"$gte": 4096}
|
| 126 |
+
gradient_checkpointing: false
|
| 127 |
+
transform:
|
| 128 |
+
gradient_checkpointing: true
|
| 129 |
+
expected_recovery_fraction: 0.4
|
| 130 |
+
expected_impact: >-
|
| 131 |
+
Enables freeing activation memory to enlarge batch size at long context;
|
| 132 |
+
typical net win 1.3-1.7x throughput at seq_len 4k-8k on MI300X despite
|
| 133 |
+
the recompute tax.
|
| 134 |
+
rocm_version_min: "6.0"
|
| 135 |
+
citation: "HF Transformers gradient_checkpointing + AMD long-context guide"
|
| 136 |
+
|
| 137 |
+
# ---------------------------------------------------------------------------
|
| 138 |
+
# data
|
| 139 |
+
# ---------------------------------------------------------------------------
|
| 140 |
+
|
| 141 |
+
- id: data.dataloader_workers_zero
|
| 142 |
+
category: data
|
| 143 |
+
targets_bucket: data_wait
|
| 144 |
+
symptom: >-
|
| 145 |
+
DataLoader num_workers=0 — the GPU stalls while the main process
|
| 146 |
+
tokenizes the next batch. Classic MI300X starvation pattern at
|
| 147 |
+
high-throughput LoRA fine-tuning.
|
| 148 |
+
detect:
|
| 149 |
+
dataloader_workers: 0
|
| 150 |
+
transform:
|
| 151 |
+
dataloader_workers: 8
|
| 152 |
+
expected_recovery_fraction: 0.8
|
| 153 |
+
expected_impact: >-
|
| 154 |
+
Spinning up 4-8 worker processes hides tokenization and host transfer
|
| 155 |
+
behind GPU compute. On MI300X with a fast NVMe dataset, this often nets
|
| 156 |
+
2x tokens/sec on its own.
|
| 157 |
+
rocm_version_min: "6.0"
|
| 158 |
+
citation: "PyTorch DataLoader best practices + MI300X fine-tuning notes"
|
| 159 |
+
|
| 160 |
+
- id: data.pin_memory_false
|
| 161 |
+
category: data
|
| 162 |
+
targets_bucket: data_wait
|
| 163 |
+
symptom: >-
|
| 164 |
+
DataLoader pin_memory=False on a CUDA/ROCm host. Each batch copy from
|
| 165 |
+
pageable host memory blocks the launch queue instead of overlapping with
|
| 166 |
+
compute.
|
| 167 |
+
detect:
|
| 168 |
+
dataloader_pin_memory: false
|
| 169 |
+
transform:
|
| 170 |
+
dataloader_pin_memory: true
|
| 171 |
+
expected_recovery_fraction: 0.5
|
| 172 |
+
expected_impact: >-
|
| 173 |
+
pin_memory=True allows asynchronous host-to-device transfer that
|
| 174 |
+
overlaps with the previous step's compute. Roughly free win, no other
|
| 175 |
+
config changes needed.
|
| 176 |
+
rocm_version_min: "6.0"
|
| 177 |
+
citation: "PyTorch CUDA/ROCm DataLoader pin_memory documentation"
|
| 178 |
+
|
| 179 |
+
- id: data.prefetch_factor_default
|
| 180 |
+
category: data
|
| 181 |
+
targets_bucket: data_wait
|
| 182 |
+
symptom: >-
|
| 183 |
+
DataLoader prefetch_factor left at the default of 2 while MI300X is
|
| 184 |
+
fast enough to drain the queue and stall before the next batch is
|
| 185 |
+
ready. Symptom: GPU util oscillates 100% → 30% in a sawtooth.
|
| 186 |
+
detect:
|
| 187 |
+
dataloader_prefetch_factor: {"$lte": 2}
|
| 188 |
+
transform:
|
| 189 |
+
dataloader_prefetch_factor: 4
|
| 190 |
+
expected_recovery_fraction: 0.3
|
| 191 |
+
expected_impact: >-
|
| 192 |
+
Raising prefetch_factor to 4 keeps two extra batches buffered per
|
| 193 |
+
worker, smoothing out the GPU-util sawtooth. Costs a few hundred MB of
|
| 194 |
+
host RAM per worker; trivial on a typical MI300X box.
|
| 195 |
+
rocm_version_min: "6.0"
|
| 196 |
+
citation: "PyTorch DataLoader prefetch_factor — long-step jitter notes"
|
| 197 |
+
|
| 198 |
+
- id: data.persistent_workers_false
|
| 199 |
+
category: data
|
| 200 |
+
targets_bucket: data_wait
|
| 201 |
+
symptom: >-
|
| 202 |
+
DataLoader persistent_workers=False — workers are torn down and
|
| 203 |
+
respawned every epoch. On large datasets the warmup tax bleeds time
|
| 204 |
+
between epochs even when the per-epoch throughput is good.
|
| 205 |
+
detect:
|
| 206 |
+
dataloader_persistent_workers: false
|
| 207 |
+
transform:
|
| 208 |
+
dataloader_persistent_workers: true
|
| 209 |
+
expected_recovery_fraction: 0.25
|
| 210 |
+
expected_impact: >-
|
| 211 |
+
Keeps DataLoader workers alive across epochs so the dataset doesn't
|
| 212 |
+
re-initialize. Removes a 5-30 second hitch at every epoch boundary on
|
| 213 |
+
Qwen2.5 LoRA workloads.
|
| 214 |
+
rocm_version_min: "6.0"
|
| 215 |
+
citation: "PyTorch DataLoader persistent_workers documentation"
|
| 216 |
+
|
| 217 |
+
# ---------------------------------------------------------------------------
|
| 218 |
+
# compile
|
| 219 |
+
# ---------------------------------------------------------------------------
|
| 220 |
+
|
| 221 |
+
- id: compile.torch_compile_off
|
| 222 |
+
category: compile
|
| 223 |
+
targets_bucket: host_gap
|
| 224 |
+
symptom: >-
|
| 225 |
+
torch.compile is disabled but the model is on the eager-mode-friendly
|
| 226 |
+
list (Qwen, Llama, Mistral, Gemma). Eager dispatch leaves host-gap
|
| 227 |
+
bubbles between MI300X kernels that compile would erase.
|
| 228 |
+
detect:
|
| 229 |
+
torch_compile: false
|
| 230 |
+
transform:
|
| 231 |
+
torch_compile: true
|
| 232 |
+
expected_recovery_fraction: 0.6
|
| 233 |
+
expected_impact: >-
|
| 234 |
+
torch.compile fuses small ops and removes Python dispatch overhead;
|
| 235 |
+
typical 1.1-1.3x throughput on Qwen-class fine-tuning on MI300X. Verify
|
| 236 |
+
no graph breaks in your forward by running with TORCH_LOGS=graph_breaks.
|
| 237 |
+
rocm_version_min: "6.0"
|
| 238 |
+
citation: "PyTorch torch.compile + ROCm support matrix"
|
| 239 |
+
|
| 240 |
+
# ---------------------------------------------------------------------------
|
| 241 |
+
# env_vars
|
| 242 |
+
# ---------------------------------------------------------------------------
|
| 243 |
+
|
| 244 |
+
- id: env.nccl_min_nchannels
|
| 245 |
+
category: env_vars
|
| 246 |
+
targets_bucket: comm_excess
|
| 247 |
+
symptom: >-
|
| 248 |
+
NCCL_MIN_NCHANNELS not set on a collective-heavy training run. RCCL on
|
| 249 |
+
MI300X benefits from a larger channel floor than the upstream NCCL
|
| 250 |
+
default to saturate the XGMI mesh.
|
| 251 |
+
detect: {}
|
| 252 |
+
transform:
|
| 253 |
+
env_vars.NCCL_MIN_NCHANNELS: "112"
|
| 254 |
+
expected_recovery_fraction: 0.35
|
| 255 |
+
expected_impact: >-
|
| 256 |
+
Setting NCCL_MIN_NCHANNELS=112 forces RCCL to use enough channels to
|
| 257 |
+
saturate MI300X XGMI bandwidth on all-reduce. Helps anywhere RCCL/NCCL
|
| 258 |
+
appears in the top kernels list.
|
| 259 |
+
rocm_version_min: "6.0"
|
| 260 |
+
citation: "AMD ROCm RCCL tuning guide — NCCL_MIN_NCHANNELS recommendation"
|
| 261 |
+
|
| 262 |
+
- id: env.numa_auto_balancing_disable
|
| 263 |
+
category: env_vars
|
| 264 |
+
targets_bucket: host_gap
|
| 265 |
+
symptom: >-
|
| 266 |
+
Linux NUMA auto-balancing left enabled — the kernel migrates pinned
|
| 267 |
+
pages between NUMA nodes during the run, causing variance and
|
| 268 |
+
occasional multi-second stalls in benchmark numbers.
|
| 269 |
+
detect: {}
|
| 270 |
+
transform:
|
| 271 |
+
env_vars.GOBLIN_HINT_NUMA_AUTO_BALANCING: "disable_via_sysctl"
|
| 272 |
+
expected_recovery_fraction: 0.15
|
| 273 |
+
expected_impact: >-
|
| 274 |
+
Disable with `echo 0 | sudo tee /proc/sys/kernel/numa_balancing` before
|
| 275 |
+
benchmarking. Removes a major source of step-time variance on MI300X
|
| 276 |
+
multi-socket boxes; required for reproducible before/after numbers.
|
| 277 |
+
rocm_version_min: "6.0"
|
| 278 |
+
citation: "AMD ROCm performance tuning — NUMA auto-balancing disable"
|
| 279 |
+
|
| 280 |
+
- id: env.hsa_force_fine_grain_pcie
|
| 281 |
+
category: env_vars
|
| 282 |
+
targets_bucket: host_gap
|
| 283 |
+
symptom: >-
|
| 284 |
+
HSA_FORCE_FINE_GRAIN_PCIE not set. Fine-grained PCIe transfers reduce
|
| 285 |
+
host→device latency for the small control packets that bracket every
|
| 286 |
+
kernel launch.
|
| 287 |
+
detect: {}
|
| 288 |
+
transform:
|
| 289 |
+
env_vars.HSA_FORCE_FINE_GRAIN_PCIE: "1"
|
| 290 |
+
expected_recovery_fraction: 0.15
|
| 291 |
+
expected_impact: >-
|
| 292 |
+
Enables fine-grained PCIe coherent traffic on MI300X. Small but
|
| 293 |
+
consistent host-gap reduction; no downside on supported platforms.
|
| 294 |
+
rocm_version_min: "6.0"
|
| 295 |
+
citation: "AMD ROCm env var reference — HSA_FORCE_FINE_GRAIN_PCIE"
|
| 296 |
+
|
| 297 |
+
# ---------------------------------------------------------------------------
|
| 298 |
+
# kernels
|
| 299 |
+
# ---------------------------------------------------------------------------
|
| 300 |
+
|
| 301 |
+
- id: kernels.hipblaslt_hint_logging
|
| 302 |
+
category: kernels
|
| 303 |
+
targets_bucket: kernel_shape
|
| 304 |
+
symptom: >-
|
| 305 |
+
Stable model + batch + seq shapes with hipBLASLt heuristic logging
|
| 306 |
+
disabled. Each step is solving a tile-selection problem the library
|
| 307 |
+
already solved; an offline-tuned hint file would eliminate the search.
|
| 308 |
+
detect: {}
|
| 309 |
+
transform:
|
| 310 |
+
env_vars.HIPBLASLT_TUNING_FILE: "/tmp/hipblaslt.tuning"
|
| 311 |
+
env_vars.HIPBLASLT_LOG_LEVEL: "1"
|
| 312 |
+
expected_recovery_fraction: 0.3
|
| 313 |
+
expected_impact: >-
|
| 314 |
+
Run once with HIPBLASLT_LOG_LEVEL=1 to capture the best tile heuristic
|
| 315 |
+
per GEMM shape, then use HIPBLASLT_TUNING_FILE to reuse it. Typical
|
| 316 |
+
win: 5-15% on long-running fine-tunes with stable shapes.
|
| 317 |
+
rocm_version_min: "6.0"
|
| 318 |
+
citation: "AMD hipBLASLt tuning + offline-hint workflow"
|
| 319 |
+
|
| 320 |
+
- id: kernels.miopen_find_mode_2
|
| 321 |
+
category: kernels
|
| 322 |
+
targets_bucket: kernel_shape
|
| 323 |
+
symptom: >-
|
| 324 |
+
MIOPEN_FIND_MODE not set. MIOpen falls back to a slow exhaustive search
|
| 325 |
+
on the first iteration of every new shape; with FIND_MODE=2 the cached
|
| 326 |
+
fast solution is reused immediately.
|
| 327 |
+
detect: {}
|
| 328 |
+
transform:
|
| 329 |
+
env_vars.MIOPEN_FIND_MODE: "2"
|
| 330 |
+
expected_recovery_fraction: 0.25
|
| 331 |
+
expected_impact: >-
|
| 332 |
+
MIOPEN_FIND_MODE=2 (FAST + DB lookup) eliminates the cold-start search
|
| 333 |
+
pause on conv/attention layers. First-step time drops dramatically;
|
| 334 |
+
steady-state perf is unchanged but warmup is cheaper.
|
| 335 |
+
rocm_version_min: "6.0"
|
| 336 |
+
citation: "AMD MIOpen documentation — MIOPEN_FIND_MODE values"
|
| 337 |
+
|
| 338 |
+
# ---------------------------------------------------------------------------
|
| 339 |
+
# optimizer (warning-only rule)
|
| 340 |
+
# ---------------------------------------------------------------------------
|
| 341 |
+
|
| 342 |
+
- id: optimizer.bitsandbytes_not_supported_warning
|
| 343 |
+
category: optimizer
|
| 344 |
+
targets_bucket: kernel_shape
|
| 345 |
+
symptom: >-
|
| 346 |
+
bitsandbytes 8-bit Adam variant configured. bitsandbytes is NOT
|
| 347 |
+
officially supported on ROCm — it may import on a community build but
|
| 348 |
+
correctness on MI300X is unverified, and AMD-validated 8-bit/quant
|
| 349 |
+
paths exist instead.
|
| 350 |
+
detect:
|
| 351 |
+
optimizer: {"$regex": "(?i)(bitsandbytes|bnb_)"}
|
| 352 |
+
transform: {}
|
| 353 |
+
expected_recovery_fraction: 0.0
|
| 354 |
+
expected_impact: >-
|
| 355 |
+
WARNING: bitsandbytes is not officially supported on ROCm. Recommended
|
| 356 |
+
alternatives are Optimum-AMD-validated paths (GPTQ/AWQ for inference,
|
| 357 |
+
8-bit Adam via Apex on ROCm, or DeepSpeed ZeRO-Offload). Do not assume
|
| 358 |
+
correctness on MI300X without your own numerical check.
|
| 359 |
+
rocm_version_min: "6.0"
|
| 360 |
+
citation: "AMD Optimum-AMD compatibility matrix — bitsandbytes status on ROCm"
|
| 361 |
+
|
| 362 |
+
# ---------------------------------------------------------------------------
|
| 363 |
+
# collectives
|
| 364 |
+
# ---------------------------------------------------------------------------
|
| 365 |
+
|
| 366 |
+
- id: collectives.one_process_per_gpu
|
| 367 |
+
category: collectives
|
| 368 |
+
targets_bucket: comm_excess
|
| 369 |
+
symptom: >-
|
| 370 |
+
Single launcher process driving multiple MI300X GPUs. ROCm serializes
|
| 371 |
+
kernel launches across devices when one process owns multiple HIP
|
| 372 |
+
streams — every collective becomes a bottleneck.
|
| 373 |
+
detect:
|
| 374 |
+
extras.launch_num_processes: 1
|
| 375 |
+
extras.world_size: {"$gt": 1}
|
| 376 |
+
transform:
|
| 377 |
+
extras.launch_num_processes: 8
|
| 378 |
+
expected_recovery_fraction: 0.6
|
| 379 |
+
expected_impact: >-
|
| 380 |
+
Use `accelerate launch --num_processes=N` (or `torchrun --nproc_per_node=N`)
|
| 381 |
+
so each MI300X has its own driver process. Removes the launch-queue
|
| 382 |
+
serialization; most multi-GPU "ROCm is slow" reports trace back to this.
|
| 383 |
+
rocm_version_min: "6.0"
|
| 384 |
+
citation: "AMD ROCm distributed training — one-process-per-GPU best practice"
|
| 385 |
+
|
| 386 |
+
# ---------------------------------------------------------------------------
|
| 387 |
+
# topology
|
| 388 |
+
# ---------------------------------------------------------------------------
|
| 389 |
+
|
| 390 |
+
- id: topology.tp_within_xgmi_island
|
| 391 |
+
category: topology
|
| 392 |
+
targets_bucket: comm_excess
|
| 393 |
+
symptom: >-
|
| 394 |
+
Tensor parallelism enabled (TP > 1) without pinning ranks to an XGMI
|
| 395 |
+
island. TP all-reduces hop across the slow inter-island link instead of
|
| 396 |
+
the fast intra-island XGMI mesh.
|
| 397 |
+
detect:
|
| 398 |
+
extras.tensor_parallel_size: {"$gt": 1}
|
| 399 |
+
transform:
|
| 400 |
+
extras.tp_placement_hint: "xgmi_island"
|
| 401 |
+
expected_recovery_fraction: 0.45
|
| 402 |
+
expected_impact: >-
|
| 403 |
+
Restrict TP rank placement to a single 4-GPU XGMI island per group so
|
| 404 |
+
all-reduces stay on intra-island links. Use ROCR_VISIBLE_DEVICES to pin;
|
| 405 |
+
prefer TP over EP on a single MI300X node.
|
| 406 |
+
rocm_version_min: "6.0"
|
| 407 |
+
citation: "AMD MI300X system topology — XGMI islands and TP placement"
|
| 408 |
+
|
| 409 |
+
# ---------------------------------------------------------------------------
|
| 410 |
+
# Bonus high-value rules to reach the 20-25 target
|
| 411 |
+
# ---------------------------------------------------------------------------
|
| 412 |
+
|
| 413 |
+
- id: precision.fp8_inference_stretch
|
| 414 |
+
category: precision
|
| 415 |
+
targets_bucket: precision_path
|
| 416 |
+
symptom: >-
|
| 417 |
+
Workload is inference / batched eval on MI300X without FP8. CDNA3 has
|
| 418 |
+
native FP8 matrix-core throughput that doubles peak vs bf16 — applicable
|
| 419 |
+
once the model has been calibrated.
|
| 420 |
+
detect:
|
| 421 |
+
extras.workload_kind: "inference"
|
| 422 |
+
transform:
|
| 423 |
+
precision: fp8
|
| 424 |
+
expected_recovery_fraction: 0.4
|
| 425 |
+
expected_impact: >-
|
| 426 |
+
Switch calibrated inference to FP8 (E4M3 weight, E5M2 grad if needed).
|
| 427 |
+
Doubles matmul peak throughput on MI300X. Requires offline calibration;
|
| 428 |
+
verify accuracy on your eval set first.
|
| 429 |
+
rocm_version_min: "6.0"
|
| 430 |
+
citation: "AMD MI300X inference guide — FP8 calibration workflow"
|
| 431 |
+
|
| 432 |
+
- id: kernels.hipblaslt_log_level_hint
|
| 433 |
+
category: kernels
|
| 434 |
+
targets_bucket: kernel_shape
|
| 435 |
+
symptom: >-
|
| 436 |
+
Top kernels show a long tail of small unfused GEMMs. Without
|
| 437 |
+
HIPBLASLT_LOG_MASK enabled the user can't see which heuristics were
|
| 438 |
+
selected and won't notice when the library falls back to a slow path.
|
| 439 |
+
detect: {}
|
| 440 |
+
transform:
|
| 441 |
+
env_vars.HIPBLASLT_LOG_MASK: "32"
|
| 442 |
+
expected_recovery_fraction: 0.1
|
| 443 |
+
expected_impact: >-
|
| 444 |
+
HIPBLASLT_LOG_MASK=32 enables heuristic-selection logging. Diagnostic
|
| 445 |
+
only — does not change perf — but lets you confirm hipBLASLt picked the
|
| 446 |
+
expected tile and switch to the offline tuning workflow when it didn't.
|
| 447 |
+
rocm_version_min: "6.0"
|
| 448 |
+
citation: "AMD hipBLASLt logging environment variables"
|
| 449 |
+
|
| 450 |
+
- id: env.miopen_user_db_path
|
| 451 |
+
category: env_vars
|
| 452 |
+
targets_bucket: kernel_shape
|
| 453 |
+
symptom: >-
|
| 454 |
+
Multiple training runs share a host but MIOpen's per-user perf DB is on
|
| 455 |
+
the default ~/.config path. First run on a new host eats the autotune
|
| 456 |
+
cost every time even though a previous run already solved the same
|
| 457 |
+
shapes.
|
| 458 |
+
detect: {}
|
| 459 |
+
transform:
|
| 460 |
+
env_vars.MIOPEN_USER_DB_PATH: "/var/cache/miopen"
|
| 461 |
+
env_vars.MIOPEN_CUSTOM_CACHE_DIR: "/var/cache/miopen"
|
| 462 |
+
expected_recovery_fraction: 0.1
|
| 463 |
+
expected_impact: >-
|
| 464 |
+
Point MIOPEN_USER_DB_PATH at a shared host directory so autotune
|
| 465 |
+
results survive container restarts and are reused across runs.
|
| 466 |
+
Eliminates first-step warm-up cost after the first build.
|
| 467 |
+
rocm_version_min: "6.0"
|
| 468 |
+
citation: "AMD MIOpen perf-db environment variables"
|