perf: Group source-projection PSUM banks to lift wide-intermediate MFU#10
Open
RuifengHua wants to merge 1 commit into
Open
perf: Group source-projection PSUM banks to lift wide-intermediate MFU#10RuifengHua wants to merge 1 commit into
RuifengHua wants to merge 1 commit into
Conversation
MLP CTE gate/up projection sized the bxs subtile count as NUM_HW_PSUM_BANKS // int_tile_count. Since each intermediate tile holds a PSUM bank across the hidden contraction loop, wide shards (I_shard >= 4096) were forced to a single bxs subtile, halving arithmetic intensity and dropping MFU to ~40%. Process the intermediate dimension in bank-sized groups instead, draining each group to SBUF before reusing its banks. This keeps live banks within the 8-bank budget while decoupling the subtile count from the int-tile count. Standard path only; quantized/MX keep the original layout via a group=None default. Measured 1.1-2.2x on TRN2 wide-intermediate configs with no regressions. Correctness verified by the shipped test_mlp_cte suite (111/111) on TRN2 including quant.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
MLP CTE gate/up (source) projection sizes the batch×sequence subtile count as
NUM_HW_PSUM_BANKS // src_proj_int_dim_tile_count(mlp_cte_tile_info.py), and the matmul assigns one PSUM bank per(bxs_subtile, int_tile)pair held live across the hidden contraction loop (mlp_cte_projection.py):So
subtiles * int_tiles <= 8. Once the intermediate shard reachesint_tiles >= 5(I_shard > 2048), the subtile count floors to 1 and stays there up to the compile limit (int_tiles = 8,I_shard = 4096).A single subtile means each weight load feeds only 128 tokens instead of 256+, halving matmul arithmetic intensity and leaving the tensor engine underutilized on wide-intermediate shards — the regime where large dense models (Llama3-70B, Qwen3-32B, Gemma3-27B) run at TP4–TP8.
Fixes #9
Scope
This changes only the standard (non-quantized) source-projection path. The quantized (STATIC/ROW) and MX paths are untouched — they keep the original bank-fitting formula, and group=None reproduces their exact prior behavior. (Extending to quant is in Future work.)
This PR
Processes the intermediate dimension in PSUM-bank-sized groups instead, draining each group to SBUF before reusing its banks for the next. This decouples the subtile count from the total int-tile count while keeping live banks within the 8-bank budget.
SrcProjPsumGroup+build_src_proj_psum_groups(groups ofNUM_HW_PSUM_BANKS // bxs_subtile_counttiles).calc_batch_seqlen_dim_tile_sizenow allows up toNUM_HW_PSUM_BANKSsubtiles (bounded by the existing 512 / token-count caps); quantized and MX keep the original bank-fitting formula.project_standard_source_tensor_tiletakes an optionalgroup; group-scoped weight DMA keeps total weight traffic at one full-width load.group=Nonereproduces the original flat bank layout exactly._perform_standard_gate_projection/_perform_standard_up_projection); the quantized/MX paths are unchanged.apply_source_projection_bias,perform_elementwise_multiply,apply_source_projection_activation) take an optionalgroupwith group-local bank indexing;group=Noneis byte-identical to the original.Results
Measured on TRN2 (neuronx-cc 2.26.6360.0), before vs after, on the final (this) commit.
real_*configs are exact per-rank shapes for dense models at real tensor-parallel degrees (see note below).Every config improves with no regressions (1.15–2.2×); the largest gains are on the previously starved wide-intermediate shards. Matmul arithmetic intensity rises from ~125 to ~470 on the wide configs. The three
(ctrl)configs (already at 2 subtiles, I_shard 2048) still improve modestly and do not regress.The
real_*configs are the per-rank shapesget_mlp_config()produces in test/integration/nkilib/core/mlp/test_mlp_cte_model_config.py for Llama3-70B, Qwen3-32B, and Gemma3-27B at TP4–TP8 — the degrees where per-rank intermediate falls in the starved regime (higher TP shrinks I_shard below it).The five starved ones gain 1.85–2.18×;
real_llama70b_TP8(I_shard 2048) is an already-healthy control and correctly shows only 1.18×.Test plan
Verified with the shipped
test_mlp_cte.py::test_mlp_cte_unitsuite on TRN2 (real compile + infer):group=Nonereproduces original bank layout)Future work(Quant Path)
The quantized dual-row path (
project_quantized_source_tensor_tile) has the samebxs_subtile * len(int_tiles) + int_tilebank assignment, so the grouping extends to it. I prototyped this and confirmed correctness on TRN2 (wide-I ROW/STATIC cases within tolerance).The gain is smaller than the standard path: dual-row already feeds ~2 rows per weight load, so even the single-subtile wide case starts at a healthy arithmetic intensity. Grouping lifts the widest shape ~44%→52% MFU, and is flat where it was already fine. In my PoC 2 subtiles beat 3 — pushing to 3 regressed back toward ~44%. I didn't fully root-cause it, but the likely reason is that more subtiles force finer PSUM-bank grouping (group_size = 8 // subtiles, so 2→4 groups here), adding drain/reload traffic that outweighs the higher per-load intensity.
A natural follow-up is to pick the subtile count per config rather than fix it, balanced against the group-count/drain tradeoff. Two ways to get there:
Simpler: size it from the allocator's live SBUF budget (
get_free_space()) minus an estimated reserve for the buffers allocated later in the pipeline. Cheap, but the reserve is an estimate, so it has to stay conservative.Correct but more involved: defer the count decision until after those buffers are allocated, so
get_free_space()reports the true remaining budget (and probe one subtile's cost instead of modeling it). No estimate, self-correcting across shapes/chips, but it's a structural change to the tiling flow.I wouldn't expect a large jump from either, but both should recover some perf on the wide-quant tail.
This is about the dual-row (STATIC/ROW) path only. MX is a separate path (project_mx_source_tensor_tile) with its own PSUM bank layout and isn't grouped here; it's also TRN3-only, so I couldn't validate it on the TRN2 setup I profiled on — a natural extension once there's TRN3 access.
Happy to discuss direction if useful.
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.