Repository navigation
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved warmup coverage and startup error-handling issues could cause request-time compilation or mask runtime failures.
Get a fresh assessment by requesting another Copilot review.
Pull request overview
Adds configurable startup prefill warmup and removes token-count specialization from FLA l2norm.
Changes:
- Adds
--skip-prefill-warmupandFREETOKEN_WARMUP_MAX_LEN. - Implements startup warmup length selection and execution.
- Updates warmup configuration and server environment handling.
File summaries
| File | Summary |
|---|---|
python/freetoken/server/args.py |
Adds the warmup opt-out flag; CLI documentation should be updated. |
python/freetoken/env.py |
Adds the warmup length cap. |
python/freetoken/engine/engine.py |
Implements warmup selection and execution; several backend, bucket-selection, error-handling, and test-coverage issues remain. |
python/freetoken/engine/config.py |
Adds warmup configuration; the default-value comment should be clarified. |
Review details
Suppressed comments (4)
python/freetoken/engine/config.py:54
- With the default value set to True, this comment describes the opposite of the field's normal behavior and makes programmatic configuration ambiguous. Document that True runs warmup and False skips it.
# skip the startup prefill warmup forwards; first requests then pay the kernel module loads (and the full JIT compile on a cold start)
python/freetoken/engine/engine.py:1065
- When
capis in [2, 8] (for example,--max-seq-len-override 8), every entry inlensis filtered out, so_warmup_prefill()performs no forward at all. This regresses the previousmin(80, max_seq_len)warmup and leaves the only reachable prefill sizes to compile on the first request; add a representative length for this small-cap range.
lens = {9, 16, 17, 32, 33, 48, 65, 80}
python/freetoken/engine/engine.py:1065
- With MXFP8 dense layers,
mxfp8_linearselectsM_TILE = next_power_of_2(M)forM <= 256(python/freetoken/kernel/triton/mxfp8_linear.py:205-216). This ladder reaches the 128 bucket at length 80 but never the 256 bucket: the 4096 sample takes the cuBLAS path (M > 256), so a first 129-256-token prefill still JIT-loads mid-request. Add a 129-token rung when the cap permits.
lens = {9, 16, 17, 32, 33, 48, 65, 80}
python/freetoken/server/args.py:751
--skip-prefill-warmupis a public server flag, but the repository's runtime option reference indocs/cli.md:37-50does not list it. Please add the default and the startup versus first-request latency tradeoff so users can discover why startup behavior changes.
parser.add_argument(
"--skip-prefill-warmup",
action="store_false",
dest="prefill_warmup",
default=ServerArgs.prefill_warmup,
help=(
"Skip the startup prefill warmup forwards. The first request at each "
"new size then pays the Triton compile/load cost mid-request."
- Files reviewed: 4/4 changed files
- Comments generated: 3
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Comment on lines
+1148
to
+1151
| except Exception as exc: | ||
| if self.config.tp_info.size > 1: | ||
| raise | ||
| logger.warning_rank0(f"Prefill warmup stopped after {done}: {type(exc).__name__}: {exc}") |
Comment on lines
+1101
to
1104
| if AttnType.DSV4 in _required_attn_types(self.config.model_config): | ||
| # DSV4 prefill reads pool.full_loc_map, which only the scheduler's paged allocation fills | ||
| logger.info_rank0("Prefill warmup skipped for DSV4.") | ||
| return |
Comment on lines
+1058
to
+1065
| def _warmup_prefill_lens(self) -> list[int]: | ||
| """Prefill lengths that cross every size bucket the in-repo Triton prefill kernels specialize on.""" | ||
| cap = min(self.max_seq_len, self.config.max_forward_len) | ||
| if ENV.WARMUP_MAX_LEN.value > 0: | ||
| cap = min(cap, ENV.WARMUP_MAX_LEN.value) | ||
| mc = self.config.model_config | ||
| # 16/32/64 BLOCK_M ladders (nvfp4_linear, fused MoE) plus an odd twin each: triton re-specializes int args on % 16 == 0 | ||
| lens = {9, 16, 17, 32, 33, 48, 65, 80} |
gdevenyi
force-pushed
the
5080/06-ple-hash-338
branch
from
September 18, 2026 03:06
fd11815 to
090dcd3
Compare
gdevenyi
force-pushed
the
5080/07-prefill-warmup-169
branch
from
September 18, 2026 03:06
e64dbef to
c3a8f01
Compare
gdevenyi
force-pushed
the
5080/06-ple-hash-338
branch
from
September 19, 2026 21:31
090dcd3 to
a699b89
Compare
gdevenyi
force-pushed
the
5080/07-prefill-warmup-169
branch
from
September 19, 2026 21:31
c3a8f01 to
84acf6e
Compare
…d-request # Conflicts: # python/freetoken/engine/config.py # Conflicts: # python/freetoken/engine/config.py
gdevenyi
force-pushed
the
5080/06-ple-hash-338
branch
from
September 23, 2026 23:36
a699b89 to
7965b58
Compare
gdevenyi
force-pushed
the
5080/07-prefill-warmup-169
branch
from
September 23, 2026 23:36
84acf6e to
4242d49
Compare
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.
Merges upstream FlashML-org#169 (
fix(engine): load prefill triton kernels at startup, not mid-request, heada8326af9). Stacked on #14.Changes
python/freetoken/engine/config.py: fix(engine): load prefill triton kernels at startup, not mid-request FlashML-org/FreeToken#169 addsprefill_warmup: bool = Truenext to a comment thatmainhad reworded from--moe-backend offloadto--moe-strategy offload. The resolution keeps the new field andmain's wording.fla/l2normstops specializing on the token count.--skip-prefill-warmup.Testing
Unit tests:
pytest tests/engine tests/server -m "not slow": 971 passed, 2 deselected.pytest tests/kernels/test_kda.py tests/models/test_glm5_next_kda_op.py tests/models/qwen4_exp/test_gdn.py(the l2norm users): 10 passed.Before the merge, on a long-running server at 150c95d (HF checkpoint dir, 4096-token prefill chunks), each prompt length never seen before was sent twice. The first send was never slower, so there was no mid-request JIT stall to remove:
(TTFT,
max_tokens1)After the merge, the deployment serves a bf16 FTW conversion (
ft checkpoint --model ~/models/Qwen3.8-Flash-Next-NVFP4 --out ~/models/Qwen3.8-Flash-Next-NVFP4-FTW) with otherwise the same flags. The Triton kernel cache on disk was warm in all runs:--skip-prefill-warmupPrefill warmup over 10 lengths: [9, 16, 17, 32, 33, 48, 65, 80, 103, 4096], completed in 18.680 s. The ladder stopped at 4096 (this run had--max-prefill-length 4096); no OOM.--skip-prefill-warmup.Environment:
nvidia/Qwen3.8-Flash-Next-NVFP4Stack: the
5080deploybranch ismaine0886cc plus upstream PRs merged one at a time for a single-user, full-context (262,144-token) deployment on this card. Each PR in the stack is based on the previous one, so its diff is exactly one merge step. Merge them in order, or merge the top of the stack alone.How tests were run: with the server stopped, since a running server holds almost all VRAM and GPU tests fail spuriously. Benchmarks are streamed chat completions with 256 tokens generated with
ignore_eos, one request at a time. Prompts are salted so the radix cache cannot hit.Rebased 2026-09-17 onto upstream main
cac247a(v0.1.3). The whole stack was rebuilt merge by merge on the new base (previous basee0886cc); the merge resolutions were replayed unchanged viagit rerere, and the rebuilt tip differs from the old one by exactly thee0886cc..cac247afile set. This PR's head is nowc3a8f01.Rebased 2026-09-19 onto upstream main
cc1f5c2(4 commits pastcac247a: FlashML-org#471 greedy sampling in mixed batches, FlashML-org#518 WeightLoadError, FlashML-org#521 tvm-ffi jit arch, FlashML-org#524 install index). Same replay as before viagit rerere; the replayed stack differs from the previous tip8adde91by exactly thecac247a..cc1f5c2file set. This PR's head is now84acf6e.🤖 Generated with Claude Code
https://claude.ai/code/session_01Bu6LgoxLR4wETqb7RPR2vt