Repository navigation
[Perf][MXFP4] Optimize activation quant for mxfp4. 3x kernel speedup, 5% throughput improvement - #63101
Conversation
Signed-off-by: ilmarkov <markovilya197@gmail.com>
9ef3ff9 to
2b96154
Compare
Signed-off-by: ilmarkov <markovilya197@gmail.com>
Signed-off-by: ilmarkov <markovilya197@gmail.com>
yewentao256
left a comment
There was a problem hiding this comment.
Thanks for the work!
Please do the following:
- shrink the diff, idealy < 500 LOC including the tests
- full reproduce command line, error log in main and the same command line works in current PR
- e2e accuracy using
lm_eval... - e2e benchmark using
vllm bench serve...
When doing reproduce / e2e test, please attach with raw output log in case some agents fake the data. DO NOT use AI generated Table here
For example:
pytest tests/v1/kv_connector/extract_hidden_states_integration/test_extraction.py::test_extract_hidden_states_tp2
# main
| (EngineCore pid=1580) File "/usr/local/lib/python3.12/dist-packages/vllm/v1/engine/core.py", line 1070, in __init__
| (EngineCore pid=1580) super().__init__(
| (EngineCore pid=1580) File "/usr/local/lib/python3.12/dist-packages/vllm/v1/engine/core.py", line 160, in __init__
| (EngineCore pid=1580) self.scheduler: SchedulerInterface = Scheduler(
| (EngineCore pid=1580) ^^^^^^^^^^
| (EngineCore pid=1580) File "/usr/local/lib/python3.12/dist-packages/vllm/v1/core/sched/async_scheduler.py", line 14, in __init__
| (EngineCore pid=1580) super().__init__(*args, **kwargs)
| (EngineCore pid=1580) File "/usr/local/lib/python3.12/dist-packages/vllm/v1/core/sched/scheduler.py", line 277, in __init__
| (EngineCore pid=1580) self.kv_cache_manager = KVCacheManager(
| (EngineCore pid=1580) ^^^^^^^^^^^^^^^
| (EngineCore pid=1580) File "/usr/local/lib/python3.12/dist-packages/vllm/v1/core/kv_cache_manager.py", line 151, in __init__
| (EngineCore pid=1580) self.coordinator = get_kv_cache_coordinator(
| (EngineCore pid=1580) ^^^^^^^^^^^^^^^^^^^^^^^^^
| (EngineCore pid=1580) File "/usr/local/lib/python3.12/dist-packages/vllm/v1/core/kv_cache_coordinator.py", line 891, in get_kv_cache_coordinator
| (EngineCore pid=1580) return HybridKVCacheCoordinator(
| (EngineCore pid=1580) ^^^^^^^^^^^^^^^^^^^^^^^^^
| (EngineCore pid=1580) File "/usr/local/lib/python3.12/dist-packages/vllm/v1/core/kv_cache_coordinator.py", line 563, in __init__
| (EngineCore pid=1580) assert all(
| (EngineCore pid=1580) ^^^^
| (EngineCore pid=1580) AssertionError: Each KV cache group's real block_size must be divisible by hash_block_size. block_sizes=[544, 544, 544, 544, 181], hash_block_size=98464
| FAILED
| v1/kv_connector/extract_hidden_states_integration/test_extraction.py::test_extract_hidden_states_tp2
# Now
================= 1 passed, 23 warnings in 174.57s (0:02:54) =================="lm_eval --model local-completions --model_args "base_url=http://127.0.0.1:9256/v1/completions,model=$MODEL,num_concurrent=1024" --tasks gsm8k --trust_remote_code"
# Now
|Tasks|Version| Filter |n-shot| Metric | |Value | |Stderr|
|-----|------:|----------------|-----:|-----------|---|-----:|---|-----:|
|gsm8k| 3|flexible-extract| 5|exact_match|↑ |0.9212|± |0.0074|
| | |strict-match | 5|exact_match|↑ |0.9212|± |0.0074|
# main
|Tasks|Version| Filter |n-shot| Metric | |Value | |Stderr|
|-----|------:|----------------|-----:|-----------|---|-----:|---|-----:|
|gsm8k| 3|flexible-extract| 5|exact_match|↑ |0.9151|± |0.0077|
| | |strict-match | 5|exact_match|↑ |0.9158|± |0.0076|
`lm_eval run --model local-chat-completions --model_args base_url=http://127.0.0.1:9256/v1/chat/completions,model=$MODEL,num_concurrent=1024,seed=256 --tasks aime25 --trust_remote_code --apply_chat_template`
# now
|Tasks |Version|Filter|n-shot| Metric | |Value | |Stderr|
|------|------:|------|-----:|-----------|---|-----:|---|-----:|
|aime25| 0|none | 0|exact_match|↑ |0.7333|± |0.0821|
# main
|Tasks |Version|Filter|n-shot| Metric | |Value | |Stderr|
|------|------:|------|-----:|-----------|---|-----:|---|-----:|
|aime25| 0|none | 0|exact_match|↑ |0.7333|± |0.0821|vllm bench serve --model zai-org/GLM-5.2-FP8 --dataset-name random --host 127.0.0.1 --port 9256 --random-input-len 8192 --random-output-len 1 --request-rate inf --num-prompts 128 --num-warmups 16
# Now
============ Serving Benchmark Result ============
Successful requests: 128
Failed requests: 0
Benchmark duration (s): 3.08
Total input tokens: 1048576
Total generated tokens: 128
Request throughput (req/s): 41.50
Output token throughput (tok/s): 41.50
Peak output token throughput (tok/s): 76.00
Peak concurrent requests: 128.00
Total token throughput (tok/s): 340041.81
---------------Time to First Token----------------
Mean TTFT (ms): 1669.15
Median TTFT (ms): 1669.02
P99 TTFT (ms): 2724.38
-----Time per Output Token (excl. 1st token)------
Mean TPOT (ms): 0.00
Median TPOT (ms): 0.00
P99 TPOT (ms): 0.00
---------------Inter-token Latency----------------
Mean ITL (ms): 0.00
Median ITL (ms): 0.00
P99 ITL (ms): 0.00
==================================================
# main
============ Serving Benchmark Result ============
Successful requests: 128
Failed requests: 0
Benchmark duration (s): 3.23
Total input tokens: 1048576
Total generated tokens: 128
Request throughput (req/s): 39.63
Output token throughput (tok/s): 39.63
Peak output token throughput (tok/s): 50.00
Peak concurrent requests: 128.00
Total token throughput (tok/s): 324671.20
---------------Time to First Token----------------
Mean TTFT (ms): 1668.69
Median TTFT (ms): 1649.00
P99 TTFT (ms): 3126.43
-----Time per Output Token (excl. 1st token)------
Mean TPOT (ms): 0.00
Median TPOT (ms): 0.00
P99 TPOT (ms): 0.00
---------------Inter-token Latency----------------
Mean ITL (ms): 0.00
Median ITL (ms): 0.00
P99 ITL (ms): 0.00
==================================================Signed-off-by: ilmarkov <markovilya197@gmail.com>
Signed-off-by: ilmarkov <markovilya197@gmail.com>
LopezCastroRoberto
left a comment
There was a problem hiding this comment.
LGTM, thanks @ilmarkov
|
✅ @ilmarkov, CI is now available for this PR.
|
|
/ci run |
|
✅ Triggered Buildkite CI #96879 for commit |
|
@yewentao256 waiting for your approval too. Can you merge if it looks good to you as well? |
|
/ci run |
|
❌ This PR is 7 commits behind upstream |
|
/ci run |
|
✅ Triggered Buildkite CI #97369 for commit |
… 5% throughput improvement (vllm-project#63101) Signed-off-by: ilmarkov <markovilya197@gmail.com> Co-authored-by: Roberto L. Castro <38211239+LopezCastroRoberto@users.noreply.github.com> Signed-off-by: Christopher Mackenzie <christopher.mackenzie.software@gmail.com>
… 5% throughput improvement (vllm-project#63101) Signed-off-by: ilmarkov <markovilya197@gmail.com> Co-authored-by: Roberto L. Castro <38211239+LopezCastroRoberto@users.noreply.github.com> Signed-off-by: Christopher Mackenzie <christopher.mackenzie.software@gmail.com>
Overview
Pass optional
sorted_expert_idsthrough Cutlass MXFP4 MoE activation quantization so each sorted token row uses a direct expert index instead of searching expert offset tables.Claims
Validation
Microbenchmark
benchmarks/kernels/benchmark_mxfp4_experts_activation_quant.pyHardware: NVIDIA B300
kernel only
mm_data + shuffle + quant
Benchmarks time
get_cutlass_moe_mm_data+ activation quant together; main and PR's paths share ~14–15 µs metadata at 256 experts (mo overhead onsorted_expert_ids), so the reported speedup is ~1.4× on the full replay while quant still saves ~5–6 µs by skipping offset lookup.E2E benchmark
vllm serve:
main:
PR:
Gsm8k validation
Details
Motivation: After MoE routing, activation rows are grouped by expert. The original path resolves each row’s expert via offset-table search; when sorted_expert_ids is already available from Cutlass MoE metadata, that search is redundant and scales poorly with expert count (microbench ~7 µs → ~2.2 µs at 256 experts).
Design: sorted_expert_ids is optional; when omitted, behavior matches offset_search.
Possible follow-up: remove redundant shared-memory expert_offsets staging in the large-m_topk MXFP4 quant kernel when sorted_expert_ids is set, and extend the microbenchmark to prefill-sized batches that hit that kernel variant.
Pull Request Checklist
I used vLLM's
/pr-checklistskill. (Mandatory for agents, optional for humans).AI assistance was used during the creation of this PR.
Design Fit: Minimizes impact on core components, reuses existing functionality, and justifies added complexity.
Testing and Validation: Validates the change and ensures any added tests are meaningful and reliable, with CI coverage or documented CI resource constraints and validation performed outside CI.
Code Quality and Style: Keeps code and comments clear and concise, and updates relevant documentation and examples.
Pull Request Contents: Includes a brief summary and relevant links, supports claims with evidence, explains root causes and implementation trade-offs, and follows the contributing guide.