Repository navigation
Conversation
…kend for GLM-5.2 GB300 TP4 low latency Add a GLM-5.2 Configuration Tips bullet recommending --flashinfer-allreduce-fusion-backend cutedsl for the GB300 NVFP4 aggregated TP4 concurrency-1 deployment: decode time per output token about 3.4% lower in three AgentX runs, TTFT not worse, GPQA-Diamond not significantly changed. It needs a build with sgl-project#45565; the bullet names the tested image and scopes the advice to concurrency 1. Also correct the --flashinfer-allreduce-fusion-backend row in server_arguments.mdx: list cutedsl, describe when SGLang auto-enables the fusion, and fix what auto resolves to on SM90. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
✅ Preview approved@nvpohanh approved a Mintlify preview for commit |
Contributor
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
nvpohanh
reviewed
Nov 5, 2026
| - **BF16 weights need more GPUs.** The full-precision build (`zai-org/GLM-5.2`, ~1.5 TB) does not fit a single 8×H200 / 8×B200 / 4×GB300 node. It fits single-node on **8×B300** (TP8, ~2.1 TB HBM) — **verified**; on the smaller GPUs it needs a **multi-node** layout (e.g. 2×8×H200 or 2×8×B200 at TP16, 2×4×GB300 at TP8), and those **multi-node BF16 recipes are still proposed/inferred** (`verified: false`). FP8 is the recommended deployment. Use the same DSA / MTP / chunked-prefill guidance as FP8. On B300, BF16 low-latency matches FP8 (the sm103 FP8 path is not yet optimized), but FP8 wins at the balanced/high-throughput points. | ||
| - **PD Disaggregation (prefill/decode).** GLM-5.2 is a DSA model and runs under prefill/decode disaggregation — toggle the **PD Disagg** card in the [Playground above](#playground) (pick a Prefill/Decode role + transfer backend, then front the roles with `sglang_router.launch_router --pd-disaggregation`). The Mooncake backend **auto-detects the InfiniBand HCA**, so no device flag is needed by default; only add `--disaggregation-ib-device mlx5_0` (your NIC) if auto-detection picks the wrong device or KV transfer fails to connect. On H200 Docker, expose the IB HCAs to the container (`--privileged --ulimit memlock=-1`, or `--device /dev/infiniband:/dev/infiniband --cap-add IPC_LOCK`) — without IB exposure Mooncake silently falls back to TCP. | ||
| - **Chunked-prefill size is regime-dependent.** At long input (8K+) the default `--chunked-prefill-size 2048` is too small and leaves the balanced point prefill-bound (queueing dominates TTFT). Raising it to `--chunked-prefill-size 32768` on the balanced recipe gave roughly **+34–78% output throughput and −39–59% TTFT** on 8×H200 and 8×B200 (8K-in / 1K-out) in our testing. It is **neutral for high-throughput** (decode-bound there) — keep the default. `--max-running-requests` tracks KV capacity, not a tuning free-for-all: ~60–90 concurrent 8K+1K FP8 requests fit on a single 8-GPU node, so pin balanced near `--max-running-requests 80` and let high-throughput run wider. | ||
| - **GB300 NVFP4, TP4, concurrency 1: add `--flashinfer-allreduce-fusion-backend cutedsl`.** It moves the fused all-reduce + residual add + RMSNorm from the default FlashInfer `mnnvl` kernels, which stop at 2048 tokens, to FlashInfer's CuTe DSL kernels, which also fuse larger prefill chunks. Added to the GB300 NVFP4 Agg TP4 concurrency-1 command in the [Agentic Long-Context section](#agentic-long-context-deployment), it lowered decode time per output token by about 3.4% in three runs without making TTFT worse, and did not significantly change GPQA-Diamond. It needs a build with [#45565](https://github.com/sgl-project/sglang/pull/45565), such as `nightly-dev-20261026-8252e3af` (tested) or newer; the image that section lists for this point, `nightly-dev-20261021-c1c287a4`, is older. On the older `nightly-dev-20261016-a93f16f0`, the flag raised p50 TTFT by about 9%. Re-measure before raising concurrency: in a microbenchmark the CuTe DSL kernel was slower than `mnnvl` at 16–20 and 96–256 tokens per call. With the flag, PyTorch kept about 8 GiB more cached memory per GPU while serving, leaving 0.45 GiB free for allocations outside PyTorch; only `--mem-fraction-static 0.83` was tested. The Deploy panel cells do not set this flag. |
Collaborator
There was a problem hiding this comment.
@akhilg-nv why don't we make this the default backend?
This branch was successfully deployed
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.
[by Claude Code]
Motivation
In every GLM-5.2 decoder layer, the attention output and the MLP output (an MoE in 75 of the 78 layers) are each summed across the tensor-parallel ranks (an all-reduce), added to the residual and normalized (RMSNorm). All-reduce fusion runs these three steps as one kernel. On one Blackwell node at TP4, SGLang turns it on by itself with
--flashinfer-allreduce-fusion-backend auto, which resolves to FlashInfer'smnnvlbackend (MNNVL is multi-node NVLink; these kernels exchange data over the NVLink fabric). That fusion covers batches of up to 2048 tokens; larger prefill chunks fall back to an NCCL all-reduce and a separate RMSNorm. The opt-incutedslbackend uses FlashInfer kernels written in CuTe DSL (CUTLASS's Python kernel language) over the same fabric. It fuses batches up to--max-prefill-tokens(8192 in this deployment) and, for batches of up to 192 tokens, also folds in the MoE finalize (the weighted sum of the selected experts' outputs) and the shared-expert add.This PR adds a Configuration Tips bullet to the GLM-5.2 cookbook that recommends
cutedslfor one deployment: GB300 NVFP4, aggregated TP4, concurrency 1 (c1), a point of the page's Agentic Long-Context section. That section lists commands measured with AgentX, SemiAnalysis InferenceX's agentic-coding benchmark, which replays recorded multi-turn coding-agent sessions against the server. The bullet gives the measured effect, the builds the flag needs (those with #45565, which raised the default prefill CUDA-graph size for MLA models from 2048 tokens to min(8192, chunked-prefill size)), the limit of the evidence to c1, and a memory note. Defaults and runtime code do not change; the default staysautobecause only this one deployment was measured. The PR also corrects the server-arguments row for this flag, which does not listcutedsland saysautopicksmnnvlon SM90 (the code pickstrtllm).Impact:
mnnvlonly at 4–12 tokens, and 1.05–1.13× slower at 16–20 and 1.05–1.10× slower at 96–256 tokens, so the bullet tells readers to re-measure before raising concurrency.nightly-dev-20261016-a93f16f0the flag raised p50 TTFT by 9.0% (decode still −3.24%), so the bullet names a minimum build.--mem-fraction-static 0.83, leaving 0.45 GiB free for allocations outside PyTorch; emptying the cache brought both backends to the same level (within 0.8 GiB). No request failed.Modifications
+3 / −2 docs (2 files); no runtime code, no tests. Base:
mainatf2d31889258d22214d9541e40b1e1e6961ce95e7.GLM-5.2 Configuration Tips (
docs/cookbook/autoregressive/GLM/GLM-5.2.mdx): one new bullet. It says what the flag changes and where it was measured, gives the effect, names the build requirement ([Perf] cuda-graph: Raise MLA prefill capture default to chunked size capped at 8192 #45565; the image the Agentic Long-Context section lists for this point,nightly-dev-20261021-c1c287a4, predates it), the older-build counter-example, the c1-only scope with the microbenchmark caveat and the memory note, and says that the Deploy panel cells do not set the flag. The bullet namesnightly-dev-20261026-8252e3af(measured) or newer; the first nightly built after [Perf] cuda-graph: Raise MLA prefill capture default to chunked size capped at 8192 #45565 merged,nightly-dev-20261024-5994c559, was not measured.Server-arguments row (
docs/docs/advanced_features/server_arguments.mdx,--flashinfer-allreduce-fusion-backend): the description follows the field's help string onmainand adds facts read from the code: when SGLang turns the fusion on by itself (including the DeepSeek-V4.1 TP4 exception), the 2048-token limit oftrtllmandmnnvl, and forcutedslits TP sizes, forward modes and workspace bound, and that it turns the other fusion off for the whole process, so speculative draft layers run unfused. The options column gainscutedsl. The old row's "Defaults to auto" and "mnnvl on SM90" did not match the code (autopickstrtllmon SM90).Where each fact in the row comes from (code on
main)python/sglang/srt/arg_groups/fields/exec_.py; the options match the field'sLiteral, and the default staysNone._flashinfer_allreduce_fusion_auto_enableandprefer_custom_dsv41inarg_groups/overrides.py).autoresolves tomnnvlon Blackwell andtrtllmon SM90 single-node (_resolve_backendinlayers/flashinfer_comm_fusion.py).trtllmandmnnvlfusion:FUSE_ALLREDUCE_MAX_BATCH_SIZEinlayers/layer_boundary/residual/add_norm.py.cutedsl: TP sizes 2, 4, 8 and 16 (SUPPORTED_TP_SIZESinlayers/flashinfer_mnnvl_cutedsl.py); decode, extend and target-verify batches only (_is_supported_forward_modeinlayers/layer_boundary/fusions/cutedsl.py); workspace bound, the largest of--max-prefill-tokens,--max-running-requests, the CUDA graph batch sizes and the decode graph batch size × draft tokens (_resolve_max_m,cutedsl_moe_max_num_tokens); the other fusion is off for the whole process (uses_cutedsl_ar_fusion), and draft layers never get the CuTe DSL fusion (install_cutedsl_fusionreturnsNonein speculative scope), so they run unfused.Not changed: the AgentX panel data (
docs/src/snippets/agentx/zai-org/glm-5.2.jsx) and the Deploy panel. Each AgentX entry mirrors an InferenceX submission and links to the run that measured it. The GB300 Agg TP4 entry's run usednightly-dev-20261021-c1c287a4(before [Perf] cuda-graph: Raise MLA prefill capture default to chunked size capped at 8192 #45565) without this flag, so editing that entry here would attach a command to a run that did not measure it. The flag can enter that entry through the regular AgentX sync once an InferenceX run with it exists.Checks.
test/registered/unit/server_args/test_server_args_docs_coverage.py(the CPU CI test forserver_arguments.mdx): 4 of 4 pass with this row on a CPU checkout ofmainatcb55d77d, and a misspelled flag in the new row makestest_no_stale_rowsfail, so the test does read the row. Since then,mainhas changed none of the code this row describes (exec_.py,overrides.pyand the fusion files have no all-reduce-fusion changes up to the base commit); CI reruns the test on this base..mdxfiles: no trailing whitespace, final newlines present, no merge markers,codespellclean on the added lines. The fullpre-commit runwas not completed locally.mint validateandmint broken-linksindocs/Accuracy Tests
GPQA-Diamond (measured).
sgl-eval0.1.3 (the version pinned inpython/pyproject.toml): 198 questions × 4 repeats, thinking on, temperature 1.0, top_p 0.95 (the checkpoint's recommended sampling), max tokens 200,000, 32 client threads. Real MTP acceptance (no simulation). Server: the launch command under Speed Tests without theSGLANG_SIMULATE_ACC_*variables, plus--max-running-requests 32 --cuda-graph-max-bs-decode 32so that the 32 threads run concurrently. The two arms differ only in the flag. Build: the replicate build described under Speed Tests (Builds). The two arms ran on different GB300 nodes on different days.auto→mnnvl)cutedslThe interval contains 0, so there is no significant change. At this sample size a drop of about 2.3 points is detectable with 80% power, so a loss of about 1 point cannot be excluded.
GPQA command and dataset
The Hugging Face GPQA set is gated, so both arms read the same local file: the 198 GPQA-Diamond questions from the public OpenAI simple-evals CSV, formatted with sgl-eval's own GPQA prompt formatting (seed 42) and passed with
--from-dataset. Absolute scores may therefore differ slightly from runs on sgl-eval's own copy; the comparison is paired.Precision (code reading of SGLang
8252e3afand FlashInfer 0.7.2, plus server logs)cutedslprocess SGLang turns off its older MNNVL all-reduce for the whole process, so two non-fused all-reduces move: the target model's last-layer all-reduce (it feeds the final norm, the logits and the draft's input hidden states) and the draft (MTP) layer's all-reduces. Up to 1,365 tokens they now use SGLang's custom all-reduce, which also accumulates in FP32. For 1,366–2,048-token prefill chunks they use NCCL, which SGLang runs withNCCL_NVLS_ENABLE=0(Ring/Tree, BF16 rounding at each hop) instead of MNNVL with FP32 accumulation. The default backend already sends every chunk above 2,048 tokens through that same NCCL path.install_cutedsl_fusionreturnsNonein speculative scope, and GLM-5.2's NextN layer skips it; the logs show 78 of 78 target layers fused on each rank), andSGLANG_NVFP4_CKPT_FP8_NEXTN_MOEis not set.Speed Tests and Profiling
Which point, and why. The low-latency end: GB300 NVFP4, aggregated TP4, c1 (the GLM-5.2 GB300 TP4 point of the Agentic Long-Context section). SGLang applies this fusion only to TP deployments without DP attention or a MoE all-to-all backend, so the high-throughput DP-attention points do not use it at all. At c1 a decode step usually carries one request with 5 draft tokens, so 5–15 tokens per all-reduce. Its gain most likely comes from faster small all-reduces (inferred: in the microbenchmark below, the CuTe DSL kernel takes 0.86–0.89× the time of
mnnvlat 4–12 tokens). The same microbenchmark shows it slower at 16–20 and 96–256 tokens, which higher concurrency reaches (for example 4 or more requests with 5 draft tokens), so this PR recommends the flag only for c1.Why an AgentX replay rather than a static workload. TTFT depends on prefix-cache hits and on the sizes of the prefill chunks, and this flag's effect on TTFT depends on chunk size: the regression on the older build came from chunks above 2,048 tokens. In this trace 95.5% of prompt tokens were read from the prefix cache, and 2,049–8,192-token chunks were 203 of 290 prefill forwards and 94.5% of new prefill tokens (default arm; counts include the client's warm-up phase). A fixed-length random workload would not reproduce that mix. Decode time per token was measured in the same runs.
Setup (measured). One GB300 node, 4 GPUs, image
lmsysorg/sglang:nightly-dev-20261026-8252e3af, modelnvidia/GLM-5.2-NVFP4, the AgentX command for this point launched withsglang.launch_server(no Dynamo frontend), AgentX client 1.0.7 at c1, simulated MTP acceptance 3.33 (InferenceX's golden value). One node per run, fresh server per arm, 1,200 s windows, order: warm-up, default,cutedsl, default. Run 1 used the image's own SGLang; the replicate and the GPQA runs used a newer SGLangmaintree laid over the same image, whose files on the flag's path are identical to the image's except for an opt-in row cap that was left unset (Builds, below).Setup details, builds, launch and client commands
lmsysorg/sglang:nightly-dev-20261026-8252e3af(sha256:b4e4abb9e1dc038f7e14c85805be97e4f74abb46e541bd4edd31401d50a2e593), FlashInfer 0.7.2, PyTorch 2.14.1+cu130. Modelnvidia/GLM-5.2-NVFP4.8252e3af). The replicate and both GPQA arms used the same image with SGLang's Python tree replaced by a newermain(316ff4dce2, 47 commits after8252e3af) plus one unmerged commit that adds an opt-in environment variable capping the rows the CuTe DSL fusion takes; the variable was unset in these runs, so behaviour is unchanged (code reading). On the flag's path, six files are identical in316ff4dce2and8252e3af:layers/flashinfer_mnnvl_cutedsl.py,layers/flashinfer_comm_fusion.py,layers/layer_boundary/fusions/cutedsl.py,layers/layer_boundary/residual/add_norm.py,model_executor/runner/base_runner.pyanddistributed/bootstrap.py; the unmerged commit adds the cap to five of them.models/deepseek_v2.py, where GLM-5.2 installs the fusion, differs between the two only by ahasattr→is not Nonechange from [Fix] deepseek-v4: Fix DeepSeek-V4 non-EP TBO for attention TP > 1 #33250.enable_thinking=true, temperature 1 and top_p 0.95.cutedsl, default.--flashinfer-allreduce-fusion-backend cutedsl(thecutedslarm only);sglang.launch_serverserves the client directly, instead ofdynamo.frontendin front ofdynamo.sglang. With one worker the frontend has no routing choice to make; that it adds only host-side request handling is an estimate, not measured;nightly-dev-20261026-8252e3afinstead of the listednightly-dev-20261021-c1c287a4, which predates [Perf] cuda-graph: Raise MLA prefill capture default to chunked size capped at 8192 #45565;NCCL_MNNVL_ENABLE=1, which InferenceX's GB300 workers also had from their environment (the recipe does not set it);--enable-metrics --enable-cache-report(logging only) and theSGLANG_SIMULATE_ACC_*variables, which InferenceX's harness also sets.Auto-enabling FlashInfer AllReduce Fusion (auto) for GlmMoeDsaForCausalLMandbackend=mnnvl. Thecutedslarm logsPrepared the FlashInfer MNNVL CuTe DSL fusion workspace for M_max=8192 (78 fused layers)on each of the 4 ranks and nomnnvlworkspace.cutedslarm also logsMNNVL CuTe DSL: no shipped profile for tp=4 hidden=6144 top_k=8; re-targeting the GB300 presets at this shape ... benchmark against --flashinfer-allreduce-fusion-backend mnnvl before deploying a shape that matters.This A/B is that benchmark.Launch command (the
cutedslarm; the default arms omit the last line):NCCL_CUMEM_ENABLE=1 \ NCCL_MNNVL_ENABLE=1 \ SGLANG_TIMEOUT_KEEP_ALIVE=900 \ TORCH_DISTRIBUTED_DEFAULT_TIMEOUT=1800 \ SGLANG_SIMULATE_ACC_LEN=3.33 \ SGLANG_SIMULATE_ACC_METHOD=match-expected \ SGLANG_SIMULATE_ACC_TOKEN_MODE=real-draft-token \ python3 -m sglang.launch_server \ --model-path nvidia/GLM-5.2-NVFP4 --served-model-name nvidia/GLM-5.2-NVFP4 \ --host 127.0.0.1 --port 30000 \ --trust-remote-code --quantization modelopt_fp4 \ --tensor-parallel-size 4 --expert-parallel-size 1 \ --kv-cache-dtype fp8_e4m3 --bf16-gemm-backend cutedsl \ --chunked-prefill-size 8192 --max-prefill-tokens 8192 --context-length 1048576 \ --mem-fraction-static 0.83 --max-running-requests 8 --cuda-graph-max-bs-decode 8 \ --speculative-algorithm EAGLE --speculative-num-steps 4 \ --speculative-eagle-topk 1 --speculative-num-draft-tokens 5 \ --enable-hierarchical-cache --hicache-size 100 --hicache-write-policy write_back \ --hicache-io-backend direct --hicache-mem-layout page_first_direct \ --tool-call-parser glm47 --reasoning-parser glm45 \ --weight-loader-prefetch-checkpoints \ --model-loader-extra-config '{"enable_multithread_load":true}' \ --watchdog-timeout 1800 --enable-metrics --enable-cache-report \ --flashinfer-allreduce-fusion-backend cutedslClient command (each arm):
AIPERF_REQUIRED_SERVER_METRIC_PREFIX=sglang: \ AIPERF_HTTP_TCP_USER_TIMEOUT=900000 \ agentx profile --url http://127.0.0.1:30000 --model nvidia/GLM-5.2-NVFP4 \ --tokenizer nvidia/GLM-5.2-NVFP4 --tokenizer-trust-remote-code \ --benchmark-duration 1200 --concurrency 1 \ --extra-inputs '{"chat_template_kwargs":{"enable_thinking":true},"temperature":1,"top_p":0.95}' \ --warmup-grace-period 1800 --public-dataset semianalysis_cc_traces_weka_062126Results, run 1 (measured; the image's own SGLang). Each arm completed 149 requests; the 148 with at least 2 output tokens are paired by conversation and turn. Decode ms/token = (latency − TTFT) / (output tokens − 1). How each row compares
cutedslwith the defaults:cutedsl/ default, pooled over both default arms (296 ratios);cutedslrequests against the same percentile of the 296 requests of both default arms taken together;Intervals are 95% paired-bootstrap intervals that resample requests (2,000 draws; 10,000 for the per-request decode ratio, where each draw keeps both of a request's ratios). Noise = second default arm vs first. A change counts as beyond noise when it is larger than the noise and both
cutedsl-vs-default pairs have the same sign.cutedslcutedslvs defaults [95% CI]nightly-dev-20261021-c1c287a4, Dynamo frontend, 3,600 s, client 1.0.12) is 5,173 tok/s/GPU at 279.3 tok/s/user p90 interactivity; the default arms here measured 5,151 and 5,156 tok/s/GPU at 272.3 and 272.2 (shorter window, no Dynamo frontend, older client).Replicate, run 2 (measured; newer
maintree)Same image, flags, client and arm order, on another GB300 node, with the newer
maintree described under Builds. 148 paired requests.Run 3: memory check (measured; 900-s windows)
Same image (its own SGLang), flags and arm order on a third GB300 node, with 900-s windows and no warm-up, to test the memory note below; 106 paired requests. Its perf numbers are reported but were not a decision input.
An earlier run, excluded
An earlier run on the same image was discarded: a shared-filesystem outage on the test cluster froze one default-backend arm for about 14 minutes. The server was waiting on a read from its Triton kernel cache, which sat on that filesystem; an unrelated process on the same node froze over the same interval, and both resumed when the storage recovered (attributed from timing and file-access records; no stack sample was taken). SGLang is not implicated. Over the 74 requests that arm completed, the run's valid default-vs-
cutedslpair agreed with the runs above (p50 decode time per token −3.24%).Counter-example on an older build (measured). On
nightly-dev-20261016-a93f16f0(which reports SGLangc15edf31, the image's build commit; FlashInfer 0.7.1), prefill CUDA graphs stopped at 2,048 tokens, so larger chunks ran eagerly. The same A/B (default /cutedsl/ default, 1,200 s each, one node) gave decode −3.24% [−3.50, −3.03] (per-request ratio), but raised TTFT p50 from 274.7 ms to 299.5 ms (+9.0%; +9.6% over the paired requests). #45565 raised the MLA prefill CUDA-graph cap to min(8192, chunked-prefill size). With it, every 2,049–8,192-token chunk in runs 1 and 2 ran in a CUDA graph, and p50 TTFT no longer rises. The mechanism is not isolated: the two builds also differ in other commits (for example #43216, which changes NCCL graph registration) and in FlashInfer version.All-reduce microbenchmark on GB300 (measured)
One GB300 node, TP4, hidden size 6144, BF16, in the image under test with SGLang's own wrappers. Every arm runs in a CUDA graph; the time is the maximum over ranks, legs are interleaved, and the result is the median of leg medians. CuTe DSL all-reduce + residual + RMSNorm against the
mnnvlfused kernel, with the CuTe DSL workspace sized for 256 tokens (at 256 tokens the 8,192-token workspace gives the same ratio, 1.08):mnnvltimeWith the 8,192-token workspace, CuTe DSL took 0.92–1.00× the time of
mnnvlat 384–2,048 tokens, and 0.71–0.77× the time of NCCL + RMSNorm (what the default runs there) at 3,072–8,192 tokens.GPU memory headroom (measured)
cutedslarms on this image (runs 1-3 and the excluded run), GPU memory in use while serving (nvidia-smi) settled about 8 GiB per GPU above the default arms: about 276.2 GiB against 268.2 GiB, out of 277.5 GiB. It then stayed flat for the rest of each window./continue_generationwithtorch_empty_cache. PyTorch's reserved memory went from 271.8 to 231.3 GiB with the flag and from 263.0 to 231.3 GiB without it (each rank logs it), and nvidia-smi then read 235.7 GiB with the flag against 236.5 GiB for both default arms. So the extra 8 GiB was idle cache, which PyTorch reuses and frees when an allocation fails; at startup the flag uses about 0.8 GiB less.cutedslarm logged 64 warnings when Triton kernels were first loaded during serving (16 loads of 8 distinct kernels on each of 4 ranks, most at the first moment two requests were running):Triton kernel '...' device-loaded after serving started (free device mem: 0.45 GiB). Pre-load it during engine init to avoid CUDA OOM.No default arm logged it (threshold 1 GiB). Every load and request succeeded.--mem-fraction-static 0.83at c1 was tested with this flag. A lower fraction may not restore headroom, because the indexer's scratch budget during prefill graph replay is 0.2 × (1 − mem-fraction-static) × GPU memory (code reading), so the cache can grow into the freed memory too.Checklist
Review and Merge Process
/tag-and-rerun-ci,/tag-run-ci-label,/rerun-failed-ciAI assistance: this PR was prepared with Claude Code; claude-opus-5-5 was the only model used (the lead agent and all subagents).
🤖 Generated with Claude Code
CI States
Latest PR Test (Base): ✅ Run #40880328379
Latest PR Test (Extra): ❌ Run #40880328449
Latest PR Test (AMD ROCm 10): ➖ No AMD PR run found for this commit.