Repository navigation
Conversation
… the same prompt (Niko1221#4059) A request for one token's logprobs (or "strata_deterministic": true) is read canonically: its prompt in one batched part with every expert on the GPU, its one-token window with every routed expert treated as a miss (over PCIe where pinned, else the CPU: the same path every time, whatever the cache holds), no low-rank expert skipped, no cached prefix reused. Its logprobs then depend on the prompt alone, while every other request keeps the adaptive tier, the PCIe share, the prefill CPU share and the tail skip, and their speed. Engine: GEN key canon=1. It sets the request's pcie_frac to 1, pauses STRATA_ROUTE_TAIL_SKIP (pause_tail_skip) and the prefill CPU share (Prefill::pause_cpu_share) for this request only, reads no prompt part through the windows, takes no turn checkpoint, skips the live session, checkpoints, batch slots and parked conversations as reuse sources, and runs its window with the residency tables cleared (restored right after, before the next adaptive round). Server: canonical_read() decides; sampling_keys sends canon=1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cix1XJhNhNNuKXi26KvXnU
gdevenyi
added a commit
to gdevenyi/AnyJev
that referenced
this pull request
Oct 29, 2026
…iko1221/Strata#4604) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Cix1XJhNhNNuKXi26KvXnU
This was referenced Oct 29, 2026
gdevenyi
marked this pull request as ready for review
October 29, 2026 13:21
This was referenced Oct 29, 2026
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.
Problem and result
A typed decision (Jev/AnyJev style) reads its answer from one token's logprobs and compares them with its other reads: a label prior, a calibrated threshold, the same question in another option order. It therefore needs the same numbers for the same prompt. Today they move from request to request. #4059 measured this on Ada, Pascal and Blackwell cards: up to ~0.5 nat, and the top answer flips on near-ties. The cause is that each expert is computed by one of several paths, and the paths round differently:
STRATA_ROUTE_TAIL_SKIP).Until now the only fix was server-wide:
--adapt-swaps 0 --pcie-frac 0 STRATA_PREFILL_CPU_SHARE=…. That costs every request about 35% of decode speed.This PR makes it per request. A canonical read takes the same path for every expert, whatever the cache holds. Every other request keeps all the adaptive paths, so chat is as fast as before.
Related discussion
StrataBackend, which reads this route withallowed_token_idsandreturn_tokens_as_token_ids) and New: anyjev.serve --backend strata, the gateway's Decider mode (stacks on #20) nokia-applied-research/AnyJev#21 (its HTTP decision gateway,anyjev.serve --backend strata, one gateway per Strata server). The scope discussion on the AnyJev side is Strata backend (anyjev/backends/strata.py) and a Decider mode for the gateway: scope check (#20, #21) nokia-applied-research/AnyJev#22. The gateway defaults to acontent_freelabel prior, so with canonical reads the same decision request gets bit-identical probabilities however much other traffic came before it. Measured behind a LiteLLM pass-through: the same request twice gave billing 0.9990941558694965 both times on the RTX 5080./v1/chat/completionsas is, and on/v1/completionsonce those land (tested combined; see below).Approach
How each source was found (bisected on hardware, one setting at a time; details in #4059):
pause_tail_skip).Prefill::pause_cpu_share). A paused chunk doesn't take the CPU pool, so every expert runs on the GPU, exactly as withSTRATA_PREFILL_CPU_SHARE=0, and the share's measured state is left alone.--adapt-swaps 0they were exact, so residency was the last variable.host_resandd_resare cleared, the window runs, and both are restored. The pending swaps land first (apply_pending(true)), so nothing is in flight.Compatibility: requests that don't qualify are unchanged, apart from two relaxed atomic loads (the pause flags) on paths they already take. The server always sends
canon=1for qualifying requests; an older engine skips unknown keys.Validation
Revision:
576badfaonmain46c152a1. Hardware runs used the same C++ plus #3332 + #4056 (for/v1/completions), built from source:-DSTRATA_EXPERIMENTAL_SM60=ON,g++-14, Linux.Both ran Qwen3.8-Flash-Next IQ3_S with the launch defaults
strata launchwrites:--expert-cache auto --prefill auto --spec 4 --spec-min-p 0.5 --mtp … --kv int8 --ple-io ram --kv-resident 32768,--parallel 1, with the adaptive tier, tail skip, PCIe share, CPU share and prompt cache all on.The workload was AnyJev's parity script, traced: 65 reads per run (15 named-id reads, 15 top-20 reads, the
Decider's 35 rotation reads), compared value by value across runs.Passed:
epic: 4 runs identical to the bit. Between runs, the cache was churned (a 3,051- and a 1,032-token plain read, 4 chat generations), and the 4th run came after a restart. The
Decider's results were identical too.monster: the same 4-run protocol, all identical.
The fix is necessary: before step 4, monster differed on 56 of 65 reads after one run, and on all 65 after chat.
Chat decode (4 prompts × 256 tokens, median), measured with requests that don't qualify:
Read cost: a canonical read costs what a first read of its prompt does.
The epic plain read is slower because a plain read splits at the turn and reads the tail through windows.
python -m unittest discover -s serve -p 'test_*.py': 1,221 tests, 1 failure, the pre-existingGpuChoice.test_hip_ordinalthat unmodifiedmainalso fails here.serve.test_logprobs: OK. That includes 4 new tests forcanonical_read/canon=1: auto-detection, non-qualifying requests, the field overriding in both directions, and a non-bool field falling back to auto.Failed:
test_hip_ordinal.Not run:
expert_source.cpp,prefill.cppandgenerate.cpp, which they compile.--parallelbatch slots with canonical reads. The window override covers the main table and every stage's copy (res_upload), but peer/remote experts aren't misses to the plan, and batch slots weren't tested.Limits
"strata_deterministic": trueandmax_tokens> 1, the window override applies to every window of the reply, so decode is slower for that request. The automatic detection never does this.Merge danger
Door: two-way. It's per request and opt-out-able (
"strata_deterministic": false), and other requests are unchanged.Blast radius: small. The one behaviour change for existing clients: a one-token logprobs request now reads its whole prompt (no reuse) and gets canonical values, so its numbers shift slightly once, then stay put.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Cix1XJhNhNNuKXi26KvXnU