Repository navigation
Conversation
3601009 to
ef66b15
Compare
cuBLASLt's heuristic picks an algorithm per M, so a row's result can change with the number of rows in the call, and a prefix and its branch run separately round differently from one pass over the same tokens. Add cs1_gemm_create_fixed: one algorithm per weight shape (N, K, ldy), the heuristic's first choice at a reference M among algorithms without split-K, for every M. The default handle is unchanged. Bump the ABI to 7 and add a GPU test that each projection's rows match across M.
forward_shared captures each prefix with the prefix continuation from InferMatrixLab#96 and continues every branch from it, with the fixed-algorithm GEMM handle; forward_fixed is the same path without a prefix. run_window takes a GEMM handle, can capture after a continuation, and indexes the text rotary tables by position.
ef66b15 to
2ff1396
Compare
… run_window) for the worker
# Conflicts: # src/models/qwen3_5/native/src/model.rs
|
Integration note: reject unsupported execution profiles before device work
Preserve the prefix-state, scratch-growth and Graph-shape guards during conflict resolution. Add a CPU regression that proves early rejection of unsupported profiles. Device qualification should cover merged 4B and 9B, Graph off/on, reordered groups/branches, growth, ordinary-forward interleaving and recovery after invalid input. Shared-prefix output must match a full pass using the same fixed handle exactly. Any comparison with the default handle’s different arithmetic should remain a separately reported metric. Reviewed head: |
|
Agreed. Main has no unmerged or reference profile yet, so if #118 or #143 lands first I'll make |
|
@twu3202 Dependency update for the execution-profile guard we discussed: #117 is now in When integrating the unmerged/reference profiles from #118/#143, keep the agreed explicit rejection in #118 is marked merged into |
Required human contributor answers
What outcome are you trying to achieve?
Run faster on native qwen3.5 workers for requests that ask several questions about the same thing.
What is the highest-leverage variable for that outcome?
How many prefix tokens each request prefills.
How will this work move that variable rather than create busywork?
qwen3_5: run prompts that share prefixes once per prefix #99 runs a shared prefix once and continues each branch from its state. qwen3_5: add a GEMM handle with one algorithm per weight shape #98 is the pre-req of qwen3_5: run prompts that share prefixes once per prefix #99, making a GEMM row's result no longer depends on how many rows are in the call.
Who is the customer or user, and what do they actually need?
agent asking several questions about one same thing such as screenshot, and they need faster answers.
After answering the four questions: is a PR needed at all to achieve this outcome?
Yes, to answer #85.
For a bug fix: link actual observed failure evidence.
N/A, not a bug fix.
Purpose
For #85, the shared executor step of the plan (§3; PR 3 in §7), as revised in this update. It now builds on #96's prefix continuation and on #98, so it should be merged after #98; until then the diff here includes #98. This PR's own change is
2ff1396; the merges on top bring in #98 and today'smain. No worker change; #113 builds on it for Decider.Model::forward_sharedruns prompts that share token prefixes: a request prefix, then groups with their own prefix and branches. Each prefix runs once, and each branch continues from the state after it, with positions and the causal mask continuing too. It returns one final hidden state per branch, in order.run_windowinto aPrefixState: per linear-attention layer the float32 recurrent state and the last three conv inputs, per full-attention layer the prefix keys and values. Each branch then runs as its own pass from that state. The request and group states persist across calls and grow only for a longer prefix; their contents are valid only within one call, which runs eagerly and synchronizes its stream before returning, also on error.forward_fixed, in an earlier version of the tests below that also ran exact splits. The result would also depend on the prompt's siblings, since they set the common prefix. Rounding down avoids both, at the cost of up to 63 extra tokens per branch.forward_fixed, a plain pass over the full prompt with the same handle and the samerun_window, bit for bit, however the prompts are grouped. It differs fromforward, which picks algorithms per row count, by rounding.run_window: it takes the GEMM handle; it can capture after a continuation, which a group prefix needs; and for text positions it offsets the rotary tables by the window start, which no caller reached before.forward_multimodal_captureandforward_multimodal_continuebehave as before, andforward,forward_batch,forward_multimodaland CUDA Graph replay are unchanged.docs/architecture.md, the runtime README and the backend README now describe the entry point, its state and its extra memory.Test Plan
System1-Omni Version / Commit:
18cbd99, which mergesmain3e9cc33intocb8ddb3;cb8ddb3merges #98 (d8cd04f, withmainbd81983) into2ff1396;2ff1396is on #98 (d717e49), onmain0d25210.CPU: the five Rust steps in CI (format, Clippy, frontend tests, workspace tests, release build),
mkdocs build --strict, and a test of how prompts split into runs.GPU, one RTX 6000 Ada (sm_89), on the Cua-S1 4B and Open-Jev-9B exports, with random token ids:
forward_sharedagainstforward_fixedon every full prompt: request prefixes of 0, 1, 63, 64, 65, 300 and 1,000 tokens, groups with 0, 1, 70 and 128 prefix tokens, and branches of 1 to 200 tokens;forwardbefore, between and after the shared runs; invalid requests (no groups, an empty group or branch, out-of-vocabulary ids anywhere) refused, after which the model still gives the same results;CUA_S1_GRAPH=1on 9B, where the plainforwardbetween shared runs replays a CUDA Graph;main, Cua-S1 and Open-Jev-9B workers side by side;Test Result
CPU. All six commands pass on macOS, including the split test.
forward_sharedagainstforward_fixed. Every branch is bit-identical, at every request prefix length and group shape above, on 4B and 9B, and on 9B withCUA_S1_GRAPH=1. Againstforward, the difference is that of the GEMM algorithms alone: up to 1.84e-2 (4B) and 1.53e-2 (9B) relative L2 on these random prompts. That is above the plan's 1e-2 hidden-state gate and inside #92's native vs reference spread (p99 0.023), so the update proposes how to treat that comparison.State isolation. Every check passes, and the model gives the same results after the refused requests. All of the invalid requests fail validation before any GPU work, so the error path's synchronization isn't exercised by these tests.
Kernel tests. 13 of 13 pass.
Plain forward unchanged: Cua-S1 567 of 567 byte-identical (134 of them forward passes) in eager and CUDA Graph modes, and Open-Jev-9B 253 of 253 identical apart from timing, against
main0d25210.Timing (9B, random tokens, one warm call each, one request prefix and 38-token branches):
forward_sharedforwardper branchA single pass with the fixed GEMMs takes 3% less time at 64 tokens, 8% more at 1,024 and 17% more at 3,072 than
forward; the prefix pass carries that cost once per request. These are synthetic layouts with random tokens. M1's real 3,093-token prefix would rerun 21 tokens per branch. The plan's measurement on real Open-Jev requests comes with the worker PR.Demo / evidence
No demo: no worker uses the entry point yet. Test output and scripts are kept locally.
Self-review