Repository navigation
Conversation
--pipeline-windows and --adapt-async 1 excluded each other: the decode loop of
--pipeline-windows 2 adapts with windows in flight, and the asynchronous tier
assumed nothing in flight at a tick. Now --pipeline-windows 2 --adapt-async 1
run together. --pipeline-windows 1 still turns the asynchronous tier off (said
once), and so do exchange buffers that are not page-locked (that check is
kept: beside the windows every copy is queued by the loop's thread, and a
pageable source would make it a staged, synchronous copy there).
In the pipelined loop the tier's four steps advance at every verdict (after
the drafter's chain is launched, off its critical path) and, while a round is
in flight, every 0.5 ms between verdicts without counting a window. Windows
are in flight at every tick (window K+1 on the first card while the last
verifies or commits K), each one waiting on the loop's thread at every layer
(its doorbell) and planning every layer from the residency table as it is
when that layer is served. Two rules:
- no CUDA call of the tier reaches a card while a window there waits on
the loop's thread. A copy queued to a card whose window spins on a host
flag can block inside the driver until that window ends (issue Niko1221#31), and
a thread blocked there can hold up the loop the window waits for. So
beside the windows the job thread does host work alone (the choice, the
bounce copies, the RAM moves), and the loop's thread queues each card's
copies itself at that card's next gap - a moment its stage has no window
in flight: before a window is launched there, and at every tick;
- a gap of a stage after a step is also the step's fence for that card:
every window planned there before the step has completed. Step 2's
copies into the evicted slots go at a gap after step 2 (a window planned
before may still read the old expert from its slot), and step 3's RAM
moves (a new RamFence state) wait for a gap after step 3 on every card
whose layers exchanged (a window planned before may still pull an
incoming expert over PCIe from the RAM place its evicted one takes; with
STRATA_EXCHANGE_ROTATE the flip that hands that place over comes after
them too). No events, no host waits. The CPU's reads need no fence: the
pool runs inside the loop's service calls.
The device copies of the residency table are not uploaded meanwhile (a
synchronous copy; the pipelined verifiers publish every row whatever they
say): once, when the loop has drained. At the loop's end (after pl_drain)
what still waits for a gap is queued and the round in flight goes on unfenced
at the next tick, the next request's drain. An error ends the engine as
before; die() and the loop's end wait only for the job's host work. The
serial loop's asynchronous tier is unchanged.
STRATA_PIPELINE_ADAPT_ASYNC=0, read with STRATA_PIPELINE_DEBUG=1 like the
other pipeline test variables, keeps the blocking tier beside the pipelined
windows (--adapt-async 1 is then off for the run, said once at startup).
Also, as run() does: the pipelined Verifier::service's timeout prints the
verifier's diag before it releases the GPU waits and the trace after it, with
STRATA_VERIFY_TRACE=1.
Measured on 0.1.40, 4060 Ti (layers 0-19) + 5080 (20-47), i9-14900KF, 32 GB
of RAM, the resident RAM mode with the whole copy in RAM, Swift 1.5 IQ3_XXS at
160K (q4_0 KV), the stock draft layer, --trim-stage-weights, greedy, five
prompts x two rounds, decode tok/s:
- --pipeline-windows 2, blocking tier (0.1.40 as released): 93.5, 94.1
- --adapt-async 1, serial loop (0.1.40 as released): 97.4, 102.1
- both (this): 110.2, 111.3, i.e. +18% over the pipeline alone and +11% over
the async tier alone.
Stress, both on, STRATA_PIPELINE_FORCE_MISS=2 STRATA_PIPELINE_THETA=0: 12
sequential 1500-token coding requests at temperature 0.6 with an nvidia-smi
query after each (as in the stall report on Niko1221#905, since traced to Niko1221#904's
graph branches): no timeout, no degenerate answer; the tier ran 1552 rounds
(105,435 experts swapped in) at ~40 ms per round. The asynchronous tier is
not bit-exact by design (Niko1221#876), so there is no exact comparison; on 0.1.40
the serial loop itself also gives a different greedy text for a different
window size (--spec 4 vs 2: 2/4 prompts identical).
Checked: builds (MSVC + CUDA 13.3, sm_89/sm_120).
This was referenced Oct 6, 2026
Contributor
Author
|
On a hybrid Intel CPU this stack's numbers swing from run to run (98-112 tok/s on the same prompts), because the host thread shares logical processor 0 with the GPU interrupts. #1166 adds |
imanu86
added a commit
to imanu86/Strata-2080Ti
that referenced
this pull request
Oct 6, 2026
…o accanto alle finestre in pipeline Da Hardin22/Strata-DualGPU ad4eaaa (pr41/pipe-async). --pipeline-windows 2 e --adapt-async 1 insieme: il thread del job fa solo lavoro host, il loop accoda le copie di ogni scheda ai suoi vuoti (nessuna finestra in volo su quello stadio), e un vuoto dopo un passo ne e' la fence. Conflitti risolti a mano accanto al gate elastico di P3 (a_gap prima del lancio di B, pl_adapt solo senza ajob). Documentazione non portata. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
imanu86
added a commit
to imanu86/Strata-2080Ti
that referenced
this pull request
Oct 6, 2026
…eline, anche col tier asincrono Con STRATA_PIPELINE_ELASTIC=1 la coda elastica di CUDA0 agisce come passaggio d'epoca: ogni chiamata CUDA arriva a CUDA0 solo a un vuoto dello stadio 0 (nessuna finestra in volo li', la fence di Niko1221#1122). Ritiro: la coda esce da host_res, si riscrive la tabella di CUDA0 e si smappa, tutto a un vuoto. Crescita: map, zeri e riempimenti a un vuoto (al massimo STRATA_PIPELINE_ELASTIC_STEP_MIB, 128), pubblicata quando i riempimenti sono arrivati; nessun giro dei tier parte nel frattempo. Niente piu' finestre trattenute ne' sync degli stream. Coda di default 1,5 GiB (STRATA_PIPELINE_ELASTIC_TAIL_MIB), contenuti del core che ruotano, regola del core limitata ai layer di CUDA0, elastico ammesso con --resident-experts. Ogni evento scrive i suoi ms e il riepilogo i ms/finestra delle due finestre dopo gli eventi. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Owner
|
Thank you. The change in this PR is already in 0.1.40.2 as a port of the original PR with authorship kept, so this re-file is closed as a duplicate of that port. |
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.
This replaces #905, which GitHub closed when
mainwas force-pushed. #859 and #876 are in 0.1.40, so it is now one commit on the newmain(0.1.40.1).0.1.40 turns
--adapt-asyncoff when--pipeline-windows 2is set. This commit lets them run together. On a 4060 Ti + 5080 split that is +18% over the pipeline alone and +11% over the async tier alone.How
With
--pipeline-windows 2there is always a window in flight when the tier ticks (window K+1 on stage 0 while stage 1 verifies or commits K). Each window waits on the loop's thread at every layer and plans each layer from the residency table as it is when that layer is served. Two rules keep the tier out of its way:RamFencestate) wait for a gap after step 3 on every card whose layers exchanged, since a window planned before may still pull an incoming expert over PCIe from the RAM place its evicted one takes. WithSTRATA_EXCHANGE_ROTATE, the flip that hands that place over comes after them too.The tier's steps advance at every verdict, after the drafter's chain is launched, and every 0.5 ms between verdicts while a round is in flight. The device copies of the residency table are uploaded once, when the loop has drained (the pipelined verifiers publish every row anyway). At the loop's end, whatever still waits for a gap is queued and the round in flight finishes at the next request's drain.
--pipeline-windows 1and exchange buffers that are not page-locked still turn the async tier off.STRATA_PIPELINE_ADAPT_ASYNC=0(read underSTRATA_PIPELINE_DEBUG=1, like the other pipeline test variables) keeps the blocking tier beside the windows. The serial loop's async tier is unchanged.Also, as
run()already does: on a timeout the pipelinedVerifier::serviceprints the verifier's diag before it releases the GPU waits, and the trace after it withSTRATA_VERIFY_TRACE=1.Measured
0.1.40, RTX 4060 Ti 16 GB (layers 0-19) + RTX 5080 16 GB (20-47), i9-14900KF, 32 GB of RAM, Windows 11. Resident RAM mode with the whole complement in RAM, Swift 1.5 IQ3_XXS at 160K (q4_0 KV), stock draft layer,
--trim-stage-weights. Greedy, five prompts × two rounds, a fresh server per run, decode tok/s:--pipeline-windows 2(0.1.40: blocking tier)--adapt-async 1, serial loop (0.1.40)Checks
STRATA_PIPELINE_FORCE_MISS=2 STRATA_PIPELINE_THETA=0(every second guess wrong, every window speculated): 12 sequential 1500-token coding requests at temperature 0.6, with annvidia-smiquery after each, as in the stall report on Pipelined windows + async adaptive tier together (stacked on #859 and #876) #905. No timeout and no degenerate answer. The tier ran 1552 rounds and swapped in 105,435 experts at about 40 ms per round. (That stall was later traced to Verify window: PDL on sm_90+, graph branches, batched Q4_0 KV append and PLE post-ops (bit-identical) #904's graph branches plus NVML queries on Linux;STRATA_DF_BRANCHis opt-in there now.)--spec 4vs--spec 2: 2 of 4 prompts identical), so pipelined vs serial can't be compared bit for bit either.The bounded attention merge and the pipelined PLE switches (#910) are stacked on this and will follow as their own PR.