IQuestRT: Faster IQuest-Q1 Inference for Coding Agents
IQuestRT on 8 GPUs
Measured on 400 Claude Code traces
8 GPUs · TP8 · one request
IQuestRT: 3–7 drafts · vLLM baseline: 5 drafts
IQuest-Q1 · temperature=1, top-k=20, top-p=0.95.
Measured on 400 Claude Code traces at seeds 0 and 1. IQuestRT: 3.558 ms/step · 1.098 ms/output-token · 3.24 output tokens per step. Decode only; prefill, loading, and graph capture excluded.
Acceptance depends on the workload and draft policy. With up to seven drafts and one bonus token, a round can return up to eight tokens.
IQuestRT is a dedicated inference runtime for IQuest-Q1 on NVIDIA GPUs, designed to shorten the generation cycles of coding agents.
It coordinates kernels, communication, sampling, and data movement across each speculative round. The GPU chooses how far to draft and launches the next round itself, while dependent kernels prepare inputs early to reduce waiting.
Performance and measurement scope
The sweep covers seven context lengths, from 1K to 192K. It measures the same five-draft computation at each length.
IQuest-Q1 · 8 GPUs · TP8 · step cost
- 1K3.229 ms/step1,239 tokens/sUp to 2,478
- 16K3.374 ms/step1,186 tokens/sUp to 2,371
- 32K3.411 ms/step1,173 tokens/sUp to 2,345
- 64K3.472 ms/step1,152 tokens/sUp to 2,304
- 128K3.628 ms/step1,103 tokens/sUp to 2,205
- 160K3.694 ms/step1,083 tokens/sUp to 2,166
- 192K3.761 ms/step1,064 tokens/sUp to 2,127
Acceptance × 1,000 ÷ step latency. Both series use measured step costs. Eight is the K7 output ceiling; the additional drafting cost is not included in this projection.
Across the sweep, increasing context from 1K to 192K raises median step latency by 16%, from 3.23 ms to 3.76 ms.
| Hardware | 8 NVIDIA GPUs |
|---|---|
| Parallelism | TP8 (tensor parallel degree 8), one concurrent request |
| Model and precision | IQuest-Q1 block-FP8 weights; FP8 expert activations |
| Speculation | Recursive MTP, 3–7 drafts selected on the GPU; five in the context sweep |
| Sampling | Temperature 1, top-k 20, top-p 0.95 |
| Real requests | 400 Claude Code traces · 3.24 output tokens per step, measured |
| Metrics | Decode throughput and complete-round step latency |
Real-request timing covers verification, sampling, recursive drafting, cache settlement, and the final readback of the device loop’s result log. Prefill, model loading, graph capture, and graph upload are excluded.
Measurement details
Opening figure. Measured, not projected: all 400 Claude Code traces, each decoded at seeds 0 and 1 with a 4,096-token cap and the template’s stop rules, replayed from prefill snapshots. The 800 decodes returned 320,252 timed tokens in 98,831 steps: 3.558 ms/step, 3.24 output tokens per step and 1.098 ms per returned token, or 910.70 tokens/s. 797 decodes ended their turn; three reached the cap. By prompt length, the rate runs from 1,027 tokens/s under 16K to 865 tokens/s at 64K and above, mostly through acceptance (3.62 to 3.14 output tokens per step). The recorded vLLM baseline is 309.83 tokens/s with five drafts; IQuestRT now chooses three to seven. Both use TP8, one request, and temperature 1, top-k 20, top-p 0.95.
Context sweep. Real weights, seeded synthetic KV, and a five-draft step. Each context has three warm-up and 30 timed replay-plus-readback steps per round, nine rounds in each of three runs. The chart uses the median of all 27 rounds. This instrument runs one step at a time, outside the adaptive device loop.
Source scope. The opening figure, the context sweep and the step profile were measured on the same 8-GPU node. Savings quoted for individual changes come from their own paired runs.
Task checks. The shipped FP8 path scored 495/500 (99.0%) on MATH-500 with a 32,768-token generation budget, and 98.0% on the first 500 GSM8K problems with an 8,192-token budget. These runs used the corrected answer-equivalence grader; subsequent engine changes preserve the checked outputs.
Why single-request decode speed matters
A coding agent reads code, generates a change, calls a tool, and reasons about the result. Tool outputs extend its context; generation determines when its next action can begin. Decode latency accumulates across these sequential steps.
IQuest-Q1 is a sparse mixture-of-experts model for CLI agents. Its inference path combines sliding-window and full-attention layers with recursive multi-token prediction (MTP). The same physical draft layer runs repeatedly to propose candidates, which the target model verifies together. Later draft depths generally consume just one live hidden-state row.
Small computation shapes and repeated synchronization make scheduling central to performance. We measure one decode step as a complete speculative round, tracking its latency, output tokens, and time per output token.
IQuestRT execution
IQuestRT captures a small family of graphs for four to eight live verification rows. The GPU chooses additional draft depths, settles the caches, and launches the next step without a host round trip. Within each graph, dependent kernels prepare independent inputs while their producers finish.
Verify, sample, draft, and settle on the GPU. The next step starts without a host round trip.
1 committed token + 3–7 drafts4–8 live positions · 8-row kernels
Host Launch the first step → read the result log when decoding ends
Target verification
88 layers + LM headOne target pass produces the logits used to check the incoming drafts. The repeated MoE layer is expanded below.
- 87 MoE layers
MoE layer · solid arrows carry computed values; dashed arrows supply prepared weights or metadata.
Input preparation → Layer 0 (dense) → 87 MoE layers → LM head
QKV → Heads → Attention → Combine → O projection + router partials → TP8 tail + routing
Gate/Up → Down → TP8 MLP tail
QKV projection
KernelThe preceding MLP tail supplies normalized rows. The main QKV converts each weight block in registers on its way to shared memory, removing the separate FP8 shared copy. Layer 0 folds input RMSNorm into its QKV projection.
- Input
- Normalized hidden rows; block-FP8 QKV weights.
- Output
- Split-K partials for Q, K, and V.
Preparation and dependencies
- Prepare
Load, convert, and stage the immutable FP8 weights in three 32×256 blocks before the dependency wait.
- Wait for
Wait for the normalized hidden rows.
- Compute
Project all eight verification rows into QKV partials.
Accept candidates and sample the next token
One sampler kernelThe target logits and saved draft distributions meet on the GPU. No host decision separates verification from drafting.
- Local Top-2020 candidates from each rank’s 20,000 logits.
- NVLink exchangeGather 8 × 20 candidates on every rank.
- Global distributionGlobal Top-20, top-p 0.95, temperature 1.
- Accept / rejectCompare target p with draft q; draw a correction or bonus token.
One draft layer, three to seven depths
Sequential reuseDepth 0 updates the committed rows; later depths extend one live row. The first three depths always run. A device control launches each additional depth only if its predicted benefit justifies the cost.
- Depth 0Committed rows → seed
- Depth 1One live row
- Depth 2One live row
- Depths 3–6Launched conditionally
Entry + EH → TP8 EH tail → Attention block → Draft router
Gate/Up + Down → TP8 sandwich tail → LM head + sample → Continue or finish
Decisions use only completed drafts. Depth 6 always finishes the step. Blocks marked “Group” contain multiple kernels.
Settle this step and launch the next
Device controlLet n be the accepted count, y the correction or bonus token, and r the new draft count. The control settles both caches, logs the result, and continues until a stop token or the output budget.
- Next verification rows
y + r drafts + padding- Target KV
- Keep the old prefix + 1 + n positions; rewind 7 − n rows.
- Draft KV
- Keep committed positions; rewind r − 1 entries.
Where the overlap comes from
Prefetch brings likely expert weights into cache during attention. PDL starts a dependent kernel’s independent preparation before its input values are ready.
Prefetch alongside attention
On sliding layers with four or five live rows, a fitted predictor warms likely Gate/Up weights while attention runs. Wider steps skip this branch.
The two branches run concurrently.
The dashed path supplies cached weights.
The attention tail selects the experts. Predictions affect cache contents only.
Prepare before the dependency clears
Programmatic Dependent Launch (PDL) lets O projection load its weights while combine waits for attention and merges the splits. O projection reads the combined activations only after they are ready.
Execution proceeds downward.
Weights can load early; reading the combined activations still waits for combine to finish.
- live verify rows
- 4–8
- recursive draft depths
- 3–7
- host result read / request
- 1
Tokens, acceptance counts, draft decisions, and cache lengths remain on the device throughout the decode loop. The host launches its first step and reads the result log once the request reaches a stop token or its output budget. The included server streams its output, so it reads the log about every 32 tokens to emit them and check for cancellation; the reported runs decode without callbacks.
Q8 describes the eight-row kernel width. A step verifies one committed token and three to seven drafts; any remaining rows are padding. The main MoE computes only live rows. Each recursive draft depth preserves its required KV writes, then continues with one seed row.
A profiled trace step shows where the GPU time goes. Each block links to the section that shapes it.
IQuest-Q1 · 8 GPUs · TP8 · 27K-token Claude Code trace · steps 40–99
- MoE expertsGate 21.3% · Down 13.6%34.9%≈1,206 μs
By prompt: 27K 34.9% · 58K 33.5% · 86K 33.1%
- Cross-GPU all-reduce tailsAttention, with routing 12.5% · MLP 9.4%21.9%≈757 μs
By prompt: 27K 21.9% · 58K 21.8% · 86K 21.5%
- Attention63 sliding layers 10.8% · 25 full layers 7.0%17.8%≈615 μs
By prompt: 27K 17.8% · 58K 19.9% · 86K 21.1%
- QKV projection and headsQKV 5.1% · norm, RoPE and KV write 3.9%9.0%≈311 μs
By prompt: 27K 9.0% · 58K 9.0% · 86K 8.8%
- Draft depths and controlsAverages 4.17 draft depths a step8.1%≈280 μs
By prompt: 27K 8.1% · 58K 7.3% · 86K 7.3%
- O projection with the router foldComputes the router partials6.6%≈228 μs
By prompt: 27K 6.6% · 58K 6.6% · 86K 6.5%
- Verify LM head and samplerLogits, acceptance and the next token0.9%≈31 μs
By prompt: 27K 0.9% · 58K 0.9% · 86K 0.9%
- Layer 0 and the step’s prologueDense MLP and entry kernels0.9%≈31 μs
By prompt: 27K 0.9% · 58K 0.9% · 86K 0.8%
Shares of rank 0’s busy time in an nsys trace of every rank. Each kernel is credited with the time it does not overlap with earlier kernels; the expert prefetch’s side stream is not counted. The step spans 3,489 μs from its first kernel to the next step’s; 5.5 μs of the gap is the device launch of the next step (request loop). Longer prompts shift time into the full layers’ attention, from 7.0% at 27K to 9.1% at 58K and 10.5% at 86K. Recorded before the streaming K/V barrier split saved a further 4.0 μs a step.
Use the same cross-GPU read for readiness and reduction
Small-batch TP8 exchanges relatively little activation data at each boundary, but the main model has 88 layers. Synchronization after attention and the MLP therefore repeats many times. IQuestRT fuses all-reduce with residual processing and normalization, and uses the data itself to indicate readiness.
Each rank's output buffer is initially filled with NaNs. Producers replace them with computed values. Consumers read the switch-reduced result through NVLink multicast addresses. If any rank has not written an element, the reduction still contains a NaN. Once an entire vector is ready, its consumer can proceed.
The same switch read checks readiness and obtains the reduced value. Buffer rotation and carefully ordered NaN rearming make reuse safe across layers and steps. Reads that remain unready have a failure exit.
The tails now separate data readers from normalization work. Main MLP readers issue their first switch read at entry, while other threads stage normalization weights. A second reader group issues a staggered read; the first NaN-free result claims the vector and continues. This reduces the cost of an unlucky read landing just before the last producer. Buffer re-arming and vector ownership preserve the reduction result.
1Before the producers run, every rank’s output slot holds NaN. The data itself will signal readiness; no flag or barrier needs resetting.
2Seven producers have written their partials. At entry, the first readers issue a switch read through the multicast address while the norm group stages its weights.
3GPU 6 has not written yet, so the switch’s sum is NaN. That read cannot be used; the readers issue it again.
4The last producer writes. The staggered second read lands just after it, returns a NaN-free sum, and claims the vector.
5The norm group applies the residual and RMSNorm to the claimed sum. Each rank then writes NaN back over its slot in the previous call’s buffer; buffers rotate, so no reader still polls it.
Read only the KV tiles needed by the current positions
Under TP8, each GPU owns six query heads and one KV head. IQuestRT combines eight query rows and six heads into 48 matrix rows, reuses K/V within a block, and partitions work along the sequence.
Full-attention reads beyond 4,096 positions use a streaming kernel built on tcgen05 instructions. TMA transfers K/V, Tensor Cores perform QK and PV, separate warps handle softmax, and score and output accumulators reside in Tensor Memory. A four-stage buffer overlaps transfers with computation. K and V complete separate barriers, so QK begins as soon as K arrives; PV waits for V. Tensor Memory is freed after the output accumulator has been read, before the partial stores finish. These final scheduling changes preserve every MMA operand and operation order.
The current query positions determine the read extent. Full attention streams the valid KV history up to those positions and applies a causal mask at the boundary. Preallocated capacity beyond that range does not add reads. The learned attention sink has a zero value, so it contributes to the softmax denominator without requiring a concatenated K/V tensor.
1The cache is allocated for the whole budget, but history fills it only up to the eight live verification rows.
2The read extent comes from the rows’ positions alone. Splits, one per SM, divide only those tiles; only the tile holding the live rows needs a causal mask. Unused capacity is never read.
3Within a split, one warp streams each tile’s K and V by TMA into a four-tile ring. K and V complete separate barriers.
4QKᵀ for a tile issues as soon as its K lands, and the next tile’s S issues before this tile’s PV. Three other warps run the softmax.
5PV waits for the tile’s V and its softmax. At the end, the O accumulator is read once and Tensor Memory is freed before the partial stores finish.
A separate combine kernel merges the splits. For streaming attention it issues the partial loads together and uses four independent FP32 accumulation chains, shortening a serial dependency while retaining the weight and denominator calculations. Through PDL, combine also starts the output projection’s weight preparation early.
Sliding-window layers use a separate path. Their physical ring holds one additional 64-slot tile beyond the 4,096-position window. When verification writes several KV rows before reading them, those writes cannot evict history still needed by an earlier query. Every live verification row sees its complete window.
Fold routing into the attention tail
The main MoE stack no longer launches a separate router. O projection also computes partial router logits from the attention output and residual base. The attention tail reduces those FP32 partials, selects the eight experts, and publishes their weights beside the normalized expert input.
This moves routing into work the layer already performs and removes a repeated kernel boundary. The initial fold saved 88.5 μs per step on the trace replay. Later refinements staged shared attention rows once, ranked logits before the final normalization scale arrived, and assigned one softmax exponential to each lane.
1Before the fold, each MoE layer launched a separate router between the attention tail and Gate/Up: one more kernel boundary in every layer.
2O projection now runs 64 extra CTAs per rank. They write FP32 router partials into a NaN-armed slot: A from the attention output, B from the residual base.
3The attention tail already reads the switch to all-reduce O projection. Its switch read also sums the router partials over the eight ranks, giving 256 FP32 logits.
4One warp ranks the 256 logits and keeps eight experts, then stores their softmax weights with one exponential per lane.
5The weights land beside the normalized expert input, so Gate/Up starts straight from the tail. The initial fold saved 88.5 μs per step on the trace replay.
The fold uses the unrounded FP32 expression rather than routing from the rounded BF16 activation, so it changes numerical results. The draft retains its separate BF16 router. Expert prefetch remains a cache hint and never overrides either routing decision.
Prepare expert weights before routing finishes
MoE experts are selected dynamically, so their weight addresses depend on the router. Fetching those weights is a substantial cost at small batch sizes.
IQuestRT consumes the checkpoint's E4M3 weights with 128×128 block scales. After matrix computation, Gate/Up applies SiLU and multiplication, then writes the E4M3 activations needed by Down. Down uses eight warps to process a token's eight routed experts in parallel. PDL lets it prepare weights while Gate is still running.
Prefetch runs only on sliding-window layers with four or five live verification rows. A side branch predicts experts from the incoming hidden state and warms their Gate/Up weights in L2. At six to eight rows the branch ends too late and costs more than it saves, so those graphs launch no prefetch. The predictor uses a checkpoint-specific refit of the folded router weights; the final expert choice still comes from the attention tail. The reported runs used this refit, the same prefetch file the README downloads.
1The attention tail picks each token’s eight experts. Without help, Gate/Up only then starts fetching their weights, a large cost at small batch sizes.
2On sliding-window layers with four or five live rows, a side stream forks after the MLP tail and predicts the experts from the incoming hidden state.
3While attention runs, the branch warms the predicted experts’ Gate/Up weights in L2. Routing still comes from the attention tail; a wrong guess changes only what is cached.
4Gate/Up applies SiLU and the multiply and writes E4M3 activations. Down, launched with PDL, prepares its weights while Gate/Up runs; eight warps then take the token’s eight experts.
5At six to eight live rows the branch ends too late and costs more than it saves, so those graphs launch no prefetch.
Include sampling and acceptance in the execution path
IQuestRT uses the checkpoint's defaults: temperature=1, top-k=20, top-p=0.95. The draft also samples and saves its actual proposal distribution.
The 160,000-token vocabulary is distributed over eight ranks. Each rank extracts a local Top-20 from 20,000 logits. After exchanging candidates, the sampler selects the global Top-20 from 160 candidates, applies top-p, and draws a token. All ranks use the same candidates and random numbers determined by the request seed and token position, avoiding a separate broadcast of the chosen token.
Verification uses standard rejection sampling. A candidate d is accepted with probability min(1, p(d)/q(d)), where p is the target distribution and q is the draft's actual proposal distribution. At the first rejection, a replacement is sampled from normalized max(0, p−q). If every candidate is accepted, the target’s extra row supplies a bonus token: seven accepted drafts plus one bonus give a maximum acceptance length of eight. Only the drafts actually generated are eligible for acceptance. Acceptance, next-round input preparation, and KV rollback are included in decode timing.
1The 160,000-token vocabulary is split over eight GPUs, 20,000 logits each. The step checks the drafts proposed in the previous step, here five.
2Each rank keeps a local Top-20. After the exchange, every rank holds the same 160 candidates and builds the same global Top-20, top-p 0.95 distribution.
3For each draft d, the target probability p(d) meets the draft’s served probability q(d). The draft is accepted with probability min(1, p/q).
4Each tick is a random draw from the request seed and token position, so every rank reaches the same decision without broadcasting a token. d4 fails its draw, so d5 is not committed.
5The first rejection is replaced by a sample from max(0, p − q), renormalized. Had all five passed, the target’s extra row would add a bonus token.
This implements the sampling rule relative to the current verifier distribution. Numerical differences from FP8 activations or changed reduction orders still require separate qualification against a higher-precision reference.
Choose draft depth on the device
Three recursive depths always run. After each subsequent decision, a lightweight control kernel either launches the next depth or ends drafting, up to seven depths. It uses features of the drafts already generated, including their served probabilities and entropy, to estimate whether another depth is worth its cost. A draft is never discarded because of its own sampled probability.
The first three depths belong to the verification graph; later depths have separate device-launchable graphs. A skipped depth therefore executes no kernels. Against a fixed draft count, the stop rule reduced measured time per output token by 2.94% on ten held-out seeds in a paired replay.
1Every step drafts at least three tokens: depths 0–2 run inside the verification graph.
2Before depth 3, a one-CTA control predicts acceptance from the drafts so far. The predicted gain clears its threshold, so it launches depth 3’s graph from the device.
3The same check runs before depth 4. It reads only completed drafts, so no draft is discarded because of its own sampled probability.
4Before depth 5 the prediction falls short. The step ends with r = 5 drafts; depths 5 and 6 launch no kernels, and the next verify has r + 1 = 6 rows.
5Depth 6, when reached, always ends the step. Against a fixed draft count, the rule cut measured time per output token by 2.94% on ten held-out seeds in a paired replay.
Draft entry is compact too. At depth 0, one launch prepares geometry and the embedding–hidden operand before EH projection. At later depths, the EH kernel builds that operand itself, while an extra CTA prepares positions, RoPE, and the mask. The one-row computation avoids a separate entry launch without introducing a grid-wide barrier.
Keep the request loop on the GPU
The final control settles both caches, records the step’s result, and tail-launches the graph for the next verification width. A stop token or an exhausted token budget ends the chain. Launching the next graph before the boundary’s final writes is safe because the graph starts only after the current graph completes.
This removes the host read, bookkeeping, and next launch between steps. Paired replay attributed roughly 22–25 μs per step to eliminating that gap, after paying for the device launch; a leaner boundary recovered about 3 μs more. Graph upload also moved into capture, so it no longer appears in the decode clock.
1In a host-driven loop, each step ends with the host reading the result, doing bookkeeping and launching the next graph while the GPU waits.
2In IQuestRT the host launches only the request’s first step.
3Each step’s final control settles both caches, logs the result, and tail-launches the graph for the next verify width, r + 1 rows. That graph starts only after the current one completes.
4A stop token or the exhausted budget ends the chain. Tokens, acceptance counts and cache lengths stay on the GPU throughout.
5The host reads the log once. Paired replay attributed about 22–25 μs per step to removing the gap, after paying for the device launch; a leaner boundary recovered about 3 μs more.
vLLM: optimize the small-batch decode path
Alongside IQuestRT, we specialized vLLM's attention, MoE, and sampling kernels for the small shapes repeated during single-request speculative decoding, retaining the existing execution framework.
Expose more parallelism in attention
With one or six tokens and six query heads per GPU, query and head dimensions expose limited parallelism. A dedicated Triton split-KV path distributes historical KV across thread blocks, then merges partial outputs using their log-sum-exp values. The combine kernel also applies the learned-sink correction, avoiding a separate operation while preserving important BF16 rounding boundaries. Moving those boundaries can change the numerical result even when the mathematical expression stays the same.
Fuse MoE at the intermediate write
The small-batch BF16 path combines Gate/Up GEMM, SiLU, and multiplication in one kernel, writing Down's input directly to reduce intermediate traffic and launches.
The dynamic per-token FP8 path fuses SiLU, multiplication, row-wise absmax, and scale calculation, writing quantized activations directly. Each path produces the representation its downstream computation needs; the existing block-quantized FP8 fusion remains a separate specialization.
Parallelize the Top-K vocabulary scan
The first Top-K pass divides logits into tiles of 8,192, collects candidates in parallel, and performs an ordered merge. Tile maxima let later scans skip regions that cannot contribute candidates. Collection and merge add launches but reduce total sampling latency—a cost repeated at every recursive draft depth.
Scope and measured result
Hardware, tensor shape, precision, and sampling checks determine where each specialization applies. Benefits depend on which paths the workload uses.
On a different eight-GPU system, with MTP depth five and one concurrent request, replaying 400 Claude Code trace requests from ten controlled engineering sessions exceeded 322 tokens/s, an 8% improvement over that evaluation's starting point. The opening IQuestRT figure is measured on the current GPU configuration over 400 Claude Code traces.
IQuestRT applies the same principles across the complete decode round: expose enough parallel work, avoid unnecessary intermediate transfers, and account for costs repeated during drafting. Its dedicated execution path also brings communication, scheduling, and state handling into that optimization scope.
How IQuestRT became faster
Development started with fixed graphs, fused tails, and PDL scheduling. IQuest-Q1 integration brought native block-FP8 weights, recursive drafting, and default sampling into one decode path. Replay then guided a second phase: folded routing, narrower live-row work, adaptive draft depth, and a request loop controlled entirely by the GPU.
Starting from an engineer-written baseline
6.4493.526ms/step
32 / 32 · Adaptive execution
Split the streaming K/V barriers
3.526 ms/step
Let a tile’s QK start as soon as its K lands, with V on its own barrier, and free Tensor Memory before the partial stores. The change is bit-exact. The repeated trace replay recorded 3.526 ms/step, 4.0 μs below the previous checkpoint.
Experiments that did not ship
- Merge only live rows
Skip unused rows in the attention combine. The isolated saving disappears in the complete decode path.
- Roll Gate by six groups
Reduce Gate code size by rolling six groups together. Less code does not remove the exposed execution cost.
- Roll Gate by two groups
Roll two groups together to shrink the Gate further. The extra loop work makes the complete step slower.
- Poll the expert handoff
Let Gate poll expert IDs with re-arming and a bounded reissue path. The synchronization overhead outweighs the earlier start.
The sequence starts from a baseline manually implemented by engineers at 6.449 ms per step. Subsequent work kept more expert tiles in flight, replaced blocking tails, and staged inputs before their consumers waited. Later work folded routing into attention, let the GPU choose draft depth, shortened the communication tails, and fused draft entry.
How it was built
AI agents contributed implementations, experiments, debugging, and code review. Engineers defined workloads, numerical constraints, and acceptance criteria, and decided which directions to pursue and which changes to merge. The execution paths above emerged through repeated hypotheses, code changes, measurements, and checks.
Turn objectives into testable questions
We optimize real-request decode speed while tracking round latency and output tokens per round. If a change makes a round faster but also changes acceptance, both effects need their own explanation.
Tasks begin with concrete questions. How much waiting does a kernel boundary expose? Can the next layer's weights arrive earlier? If padding work is skipped, are all KV entries needed by the next step still valid? An agent reads the implementation and prior experiments, proposes a candidate and its validation, and works on an independent branch. Measurements run from committed code. Results identify the source revision, environment, command, and raw output.
Engineers use this evidence to assess the objective, the strength of the result, and whether further work is justified. For small gains, a third A/A arm rebuilds the candidate in the same way as the control: otherwise a build-dependent offset can masquerade as an optimization. Each experiment leaves a record that the next task can build on.
Let real requests correct the performance model
An early attribution experiment found that real decoding was substantially slower than a synthetic step with the same KV read length. The GPU-side difference was about 0.36 ms per step, mostly in MoE computation.
Routing explained the gap. Six live verification rows select 48 expert slots, but several rows can reuse an expert. Real requests visited an average of 37.7 distinct experts per layer, compared with 11.0 for synthetic inputs. Real routing read more distinct weights and reused the cache less.
That result changed how we evaluated MoE candidates. Synthetic runs remained useful for quick checks and context-specific measurements, but changes affecting expert access had to return to real requests. A gain on repeated-token inputs needed confirmation during actual generation.
To shorten the feedback cycle, we built prefill snapshot replay. Each fixed request executes real prefill once, saving KV and hidden states. Experiments restore that state, then run normal draft prefill, sampling, graph capture, and decode. The restored path must reproduce generation from real prefill before it can compare candidates. Control and candidate alternate in the same process, reducing repeated prefill cost and process-to-process timing drift. The tool also checks that their captured graphs actually differ, so an ineffective substitution cannot masquerade as an optimization.
Use paired experiments to define the prefetch boundary
Prefetch’s value changed as the surrounding chain became faster. We measured each verification width separately: four- and five-row steps benefited, while six- to eight-row steps lost time. Restricting the fork to the useful widths recovered 20.5–23.2 μs per step in two paired trace replays.
Prediction quality needed a separate experiment. An oracle issued exactly the experts the Gate would read, at the predictor’s existing cost, bounding the value of better guesses. Refitting the predictor’s weight matrix raised held-out expert coverage from 83.5% to 87.6% and recovered 4.0 μs per step without changing the kernel. A bias-based predictor also improved coverage, but its additional kernel work cost more than it saved.
These experiments distinguish cached bytes from scheduling effects. Prefetch’s resident CTAs and their shared-memory configuration also affect which kernels can run alongside them. More hits alone do not establish a faster decode step.
Keep the experiments that did not ship
Fuse attention combine into output projection. Output projection still needs the complete attention result; fusion does not remove that cross-CTA dependency. The tested correct synchronization schemes cost more than the eliminated kernel boundary. PDL already overlaps weight preparation, reducing the time left for fusion to recover. Combine remains separate.
Rewrite MoE Gate with native FP8 MMA. A tcgen05 prototype used TMA for weights and Tensor Memory for accumulation. Across 16 real routing patterns in isolated paired tests, the prototype combined with the existing Down was approximately 3.02 μs per layer slower. Removing its MMA work still did not give the remaining data handling an advantage. Gate failed the screen, so the Down prototype contingent on its success was not pursued.
Use FP4 expert weights. The screened encoding reduced weight storage and matched the shipped FP8 path closely on task scores, but the corresponding Gate and Down kernels did not recover that saving in execution. Unpacking, staging, and the compute schedule outweighed the smaller reads. FP4 remains an explored direction, not the runtime’s weight format.
Compute guessed experts before routing. Starting Gate weight loads from the prefetch predictor looked promising, but selecting the guesses inside Gate cost more than it hid. The paired replay was slower on every request; the shipped Gate continues to consume the final routing decision.
Push partials instead of polling the switch. Multicast stores and peer-to-peer reads did not produce a usable reduction sooner than the existing switch read, and their local sums did not reproduce its bits. The NaN-polled reduction stays.
Rejected candidates leave specific reasons behind. The host-loop direction was reopened once the runtime supported device graph launches and retained after a paired replay showed a gain. A previous limit is useful evidence, not a permanent rule.
Let correctness checks change the design
The sliding-window ring expansion came from checking a state boundary. Verification writes eight KV rows before reading. If the physical ring has exactly 4,096 slots, later writes can evict history still needed by earlier queries.
We reproduced the problem using independent position labels and visible-position sets, then expanded the ring to 4,160 slots, adding one 64-slot tile. Across 200 paired real decodes, the fix increased step latency by approximately 0.28%. We retained it because every verification row must see its complete window.
The fix also exposed a validation problem. If a control implementation contains a defect, using its error bound as a tolerance can hide real mistakes. Qualification must distinguish the positions that the defect can affect and require deliberately broken negative controls to fail.
Further investigation found numerical variation in the reference itself. Appending tokens can change the number of rows in each expert GEMM, changing rounding at earlier positions and amplifying differences through later routing. We added stability checks that append one and eight tokens to distinguish candidate errors from reference variation.
Keep the evidence with the decision
After implementing a change, the agent checks requirements, tests, and the final diff. Engineers decide whether it merges. Bit-exact scheduling changes must preserve the relevant numerical values, output tokens, and acceptance sequences. Changes to floating-point computation are checked against the reference, with acceptance changes reported separately. Both forms of validation need conditions that can fail.
Performance and numerical evidence applies to a particular source revision and environment. Later changes that affect the measured path require revalidation. Each adopted change records why it was retained; each closed direction records what would make it worth revisiting. Those records give the next agent a concrete starting point.