Repository navigation
Conversation
added 2 commits
October 29, 2026 01:15
… down At 8 rows up/gate ran each routed slot's tiles once a row, so an expert two rows picked (the shared one always) streamed once a row, and the CTAs holding the shared expert's tiles ran a tile more than the others. Its jobs are now the 8-intermediate tiles of the shared expert and of each distinct routed expert (in order of first use, found by every wave from the top-8s), each with every row that picked it as an MFMA column, dealt round-robin over the CTAs; every CTA routes, issues the activations' poll and its first job's weights, then checks the poll. Down streams each expert once too: its units multiply the tile with every using row and store the products in LDS, and each row's output is summed over its units in the order and wave segments of the one-row form. The rows the multi-column MFMAs read (the activations and the FP8 mid blocks) are padded by 4 words. A column's sums are those of a one-row tile, so mid and the output keep their bits. Up to 4 rows keep the one-row forms, which measured faster there, and dense layers keep theirs.
…tep's expert groups Down's units past the step's expert groups load no weights (their buffer is empty) and store no products, but their MFMAs still ran. A wave's weight batch whose first unit is past them now skips its MFMAs: at 8 rows a step uses about 43 of the 65 possible groups, so the last batches mostly have none. The products and sums are unchanged.
heslami
force-pushed
the
review/perf-glm53-moe-dedup
branch
from
October 29, 2026 08:40
3593602 to
32129cc
Compare
Collaborator
Author
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.
Motivation
Stacked on #TBD (the indexer launch PR) (and the stack under it). Merge those first; this PR's diff is its last two commits.
At 8 rows (MTP at two requests) the MoE stages ran every routed slot once a row. An expert that two rows picked streamed its weights twice, and the shared expert, which every row uses, ran its tiles once a row in down. At 8 rows, 8 picks a row plus the shared expert give up to 65 (row, expert) uses a step, and rows of the same requests share many of them. The MoE phase of the launch is bound by the bytes each CU streams after its first weights, so every repeated expert is time.
Up to 4 rows the repeats are few and the per-expert overheads (finding the groups, the products in LDS, the summing pass) cost about what they save, so 2 and 4 rows keep the one-row forms. Dense layers keep theirs too.
Every output and every write stays bitwise equal to the base, at TP8 and TP4, every width, on the bf16 and the E4M3 MLA cache (Accuracy Tests).
Result on MI355X, base → this PR (TP8, FP8 E4M3 KV, MTP 3-1-4 at the golden accept length 2.99, 8K):
time_layers.py, TP8): model order at 8 rows, 8K and 128K: TBD µs a launch (Speed Tests).Modifications
Two commits, one per change. Each was checked against its parent (Accuracy Tests) and timed against it (Speed Tests).
polltakes an optionalbetween()that runs after the first loads are issued and before they are checked;stage_xqpasses it through. up/gate uses it to issue the first job's weights under the activations' round trip.Accuracy Tests
All on MI355X in the image below, with the in-tree tools under torchrun at TP8 and TP4.
Bitwise (
check_layer.py --dump,--compare):shared(3 launches),index(3),model(the first 8 launches) anddense(3).NextN launches (
check_nextn.py --only entry; NextN index at 4 and 8 rows, NextN shared at 2, 4 and 8 rows): TBD at TP8 and TP4 on both caches.E2E (
test/e2e/test_glm53_server.py, TP8): TBD.GSM8K with MTP, two requests: TBD.
Unit tests: TBD.
Speed Tests and Profiling
Setup as the base: image
lmsysorg/sglang-rocm:v0.5.22-rocm720-mi35x-20261025with SGLang'spython/sglangoverlaid at5044779f,zai-org/GLM-5.3atba32f8c1, the e2e test's server flags with--kv-cache-dtype fp8_e4m3.TP8, FP8 E4M3 KV, MTP 3-1-4 at AL 2.99, cycle in ms:
TP4, FP8 E4M3 KV, MTP at AL 2.99, two requests: TBD → TBD ms.
Kernel-only (
time_layers.py, TP8, E4M3 KV, µs a launch; each commit against its parent, rounds in alternating order):Registers
TBD.
Reviewer notes
kernel.pygrows by about 470 lines, most of it the 8-row up/gate and down paths; a candidate for the stage-builder split.Checklist
pre-commit run --all-filespasses. (ruff, ruff-format and isort clean on the touched files; full run TBD)test/cover the change..github/CODEOWNERSthat names its owner. (No new model.)