Skip to content

roofline: capture per-launch MoE active-expert count (experts_used)#50

Open
roberteg16 wants to merge 1 commit into
gfx11from
rogarcia.roofline-moe-experts-used
Open

roofline: capture per-launch MoE active-expert count (experts_used)#50
roberteg16 wants to merge 1 commit into
gfx11from
rogarcia.roofline-moe-experts-used

Conversation

@roberteg16

@roberteg16 roberteg16 commented Jul 14, 2026

Copy link
Copy Markdown

Summary

MoE (MUL_MAT_ID) reads only the experts a launch actually routes, but the roofline had no measured count of them, so the consumer fell back to the shape bound min(M·top_k, E). That bound saturates to all experts and over-counts HBM traffic whenever routing leaves experts idle, making memory-bound MoE kernels read >100% of peak — physically impossible, and not cache reuse (the expert weights dwarf L2/L3). It was simply a byte over-count.

This PR emits the missing fact: the true number of distinct experts each launch routes.

  • Read the routing ids tensor back per invocation and emit it as experts_used in the JSON. It is data-dependent — it varies launch to launch — so it is captured per launch, not per shape.
  • begin_op now takes the op's stream (as void *, to keep the header free of the HIP runtime) and hipStreamSynchronizes it so the ids are final before the copy.
  • The read-back is wrapped in a sentinel correlation id (0) so any copy kernel it might lower to is attributed to no op and excluded from total_gpu_time_us. In practice the D2H copy goes through SDMA (a MEMORY_COPY record we don't subscribe to) and emits no dispatch at all — verified below.
  • All roofline figures come from per-kernel device timestamps, which a host-side sync between ops leaves untouched, so nothing in the report changes except the new field.

Notes

  • Stacked on rogarcia.roofline-fused-raw-facts (raw-facts producer), which is the PR base.
  • Consumer counterpart (uses experts_used to scale MoE weight bytes, plus mean+range aggregation and a cache-aware warning): FaaSApps/rocm-scripts#715.

Test plan

  • Builds with -DGGML_HIP_ROOFLINE=ON (gfx1151): both the CXX ggml-cuda-roofline.cpp and the HIP ggml-cuda.cu compile and link.
  • Real capture (Qwen3.6-35B-A3B, gfx1151, pp128): every MUL_MAT_ID row carries experts_used in [1, n_experts]; measured routing was mean 114, range 77–179 of 256 vs. the bound's flat 256. Decode (M=1) correctly gives experts_used = 8 = min(8, 256) — the bound was already tight there, so only prefill/batched launches change.
  • No trace contamination: 0 copyBuffer/fillBuffer/rocclr kernels in the trace and total_gpu_time_us unaffected — the sentinel-id guard was belt-and-suspenders; the SDMA copy left no dispatch.

Example output (rendered by the consumer, rocm-scripts#715)

Effect of experts_used on the mul_mat_q<q4_K,16> MoE expert matmul. Both columns are the same trace (identical 421.17 µs); "before" is the shape bound (no experts_used), "after" is the measured count.

Before (no experts_used → all 256 experts charged):

└─[GEMM] void mul_mat_q<(ggml_type)12, 16, false>(...)   421.17 µs avg
   ├─ Bytes: 146.41 MiB  = ... experts·256/256 ...  (experts read = 256 of 256, min(M·top_k, E))
   ├─ BW: 348.6 GiB/s
   └─ Peak: 100.0% (memory-bound)  ⚠ nominal 151.6% capped (roofline miscalculation: 146.41 MiB exceeds L2+L3 34.00 MiB, cannot be cache reuse)

After (measured experts_used):

└─[GEMM] void mul_mat_q<(ggml_type)12, 16, false>(...)   421.17 µs avg
   ├─ Bytes: 66.76 MiB (mean; range 45.72 MiB–103.09 MiB)  = ... experts·91/256 ...  (experts read = 91 of 256, measured)
   ├─ BW: 153.8 GiB/s
   └─ Peak: 66.9% (memory-bound)

The impossible 348.6 GiB/s (peak 230 GiB/s) collapses to a real 66.9% once only the ~91 experts actually routed are charged.

@roberteg16 roberteg16 changed the title roofline: capture per-launch MoE active-expert count roofline: capture per-launch MoE active-expert count (experts_used) Jul 14, 2026
@roberteg16 roberteg16 marked this pull request as ready for review July 15, 2026 07:12
Base automatically changed from rogarcia.roofline-fused-raw-facts to gfx11 July 15, 2026 10:31
MUL_MAT_ID reads only the experts a launch actually routes, but the byte model
had no way to know that count and the consumer fell back to the shape bound
min(M*top_k, E) -- which saturates to all experts and over-counts HBM traffic
when routing leaves experts idle, pushing memory-bound MoE kernels past 100% of
peak (the working set dwarfs L2, so it is not cache reuse).

Read the routing ids tensor back per invocation and emit the distinct
active-expert count as experts_used. begin_op takes the op's stream and
hipStreamSynchronize's it so the ids are final before the copy; the read-back is
wrapped in a sentinel correlation id (0) so any copy kernel it lowers to is
attributed to no op and skipped in the total. Device-timestamp durations are
unaffected, so the report's figures are unchanged apart from the new field.
@roberteg16 roberteg16 force-pushed the rogarcia.roofline-moe-experts-used branch from 1847907 to 5b06a86 Compare July 15, 2026 11:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants