Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
177 commits
Select commit Hold shift + click to select a range
830afe4
[None][feat] Add DSpark confidence-head verification scheduling
lancelly Jul 30, 2026
8723506
[None][fix] Fix host syncs, slot aliasing and cost model in DSpark co…
lancelly Jul 31, 2026
e1c28ee
[None][feat] Make DSpark ragged verification work on the DSv4 kernel …
lancelly Aug 1, 2026
d889704
[None][doc] Scope the DSpark ragged-verify measurements to x86 DGX B300
lancelly Aug 1, 2026
cb5cb0b
[None][fix] H1/K8: stride the DSA generation expansions by the runtim…
Aug 1, 2026
44a8193
[None][fix] Remove the two remaining per-step host syncs on the DSpar…
Aug 1, 2026
f99c34a
[None][fix] H8/K5/K6/K13: reject ragged-verify configs that cannot be…
Aug 1, 2026
b3a5fef
[None][fix] H9 + §4.4: fix the DSpark collective divergence and the A…
Aug 1, 2026
3b52d19
[None][fix] H7: let rejection sampling survive a ragged batch
Aug 1, 2026
9089763
[None][test] B2: microbenchmark the two sparse-MLA generation present…
Aug 1, 2026
7c23527
[None][test] A3/A4/A6: make ragged-layout inconsistency loud instead …
Aug 1, 2026
fb87327
[None][test] Parameterize the sparse-MLA test by query width; add com…
Aug 1, 2026
1b10b41
[None][test] Fix the generation KV allocation the width parameterizat…
Aug 1, 2026
51f8897
[None][test] Add DSpark GSM8K cases with the overlap scheduler on
Aug 1, 2026
79b6067
[None][test] Parameterize the new DSpark GSM8K cases over both MoE ba…
Aug 1, 2026
7e0c6c4
[None][test] B2: size the benchmark's KV pool for whole-block allocation
Aug 1, 2026
0c8d182
[None][test] Fix the compressor test's paged-state width
Aug 1, 2026
2c08bfa
[None][doc] DSpark P0 execution report
Aug 1, 2026
08cfb4d
[None][doc] Confirm the golden manifest is unchanged and A3 stayed si…
Aug 1, 2026
a4c462c
[None][doc] Record the DSpark unit-test results (202 passed)
Aug 1, 2026
e59c810
[None][fix] Restore runtime_draft_len after the CUDA-graph capture pa…
Aug 1, 2026
301fe8b
[None][doc] Record the runtime_draft_len leak the hang fix exposed
Aug 1, 2026
9762175
[None][fix] Publish the gen-token layout before the seq_lens refresh …
Aug 1, 2026
d3cecc6
[None][test] Let the ragged GSM8K case take an SPS cost table
Aug 1, 2026
01625c9
[None][fix] Make the DSpark "did the feature do anything" gate usable
Aug 1, 2026
ccaf9c4
[None][test] Add an opt-in CUDA sync detector for the DSpark decode path
Aug 1, 2026
05c67cf
[None][fix] TLLM_DSPARK_ASSERT_ACTIVE takes a step floor, not a boolean
Aug 1, 2026
742ce5d
[None][feat] Record whether trimming actually cost acceptance
Aug 2, 2026
46be768
[None][doc] Record the sync audit, kernel-compat proof and the new tr…
Aug 2, 2026
3b3568a
[None][doc] K1 blocks ragged verification on DSv4; the PR never addre…
Aug 2, 2026
1f11daf
[None][doc] Theta is real and large; correcting an earlier prediction
Aug 2, 2026
70eab5d
[None][test] Let the uniform-tier GSM8K case take an SPS cost table too
Aug 2, 2026
d4247bb
[None][doc] GSM8K = 96.2092, and the counters say it is a baseline
Aug 2, 2026
9dd87cf
[None][feat] Present DSv4 generation token-major so ragged verificati…
Aug 2, 2026
fdedeaa
[None][fix] Size the attention op's semaphore array for token-major rows
Aug 2, 2026
2a53cd8
[None][chore] Make a zero-sample SPS cell explain itself
Aug 2, 2026
9370b06
[None][fix] Expand the token-major block table on the sequence axis
Aug 2, 2026
6e7c344
[None][fix] Get more SPS samples by repeating cells, not lengthening …
Aug 2, 2026
f2073b8
[None][fix] Present request types and prompt lens token-major too
Aug 2, 2026
3b720c6
[None][chore] Record the measured workspace cost of the row-count cap…
Aug 2, 2026
febb925
[None][fix] Average only numeric lm-eval metrics
Aug 2, 2026
f9abb75
[None][chore] Record which shape a ragged CUDA graph miss submitted
Aug 2, 2026
dcb64eb
[None][fix] Run the DSpark ragged gate mid-loop so it can fail the run
Aug 2, 2026
e8c6364
[None][fix] Attribute ragged CUDA-graph misses to a reason
Aug 2, 2026
e86cbf7
[None][fix] Average only lm-eval metrics, not sample counts
Aug 2, 2026
7da09a2
[None][fix] Count the ragged gate's floor over populated batches
Aug 2, 2026
4622883
[None][fix] Reclaim KV reserved for verify positions ragged trimmed away
Aug 2, 2026
5ddd6b5
[None][fix] Reject enable_ragged_verify without a profiled cost table
Aug 2, 2026
468e868
[None][doc] Record what the P0 stage actually measured
Aug 2, 2026
626b5dc
[None][doc] Stop telling users to force windows to bootstrap a table
Aug 2, 2026
f62bf13
[None][refactor] Drop TLLM_DSPARK_FORCE_VERIFY_LENS for a crafted cos…
Aug 2, 2026
2c7cd47
[None][test] Emit a steep SPS table so the planner exercises ragged v…
Aug 2, 2026
17b81ff
[None][test] Catch steep tables that cannot induce trimming, before t…
Aug 2, 2026
9103fd3
[None][test] Preview with the real planner instead of re-deriving its…
Aug 2, 2026
d766fae
[None][doc] Correct the memory section: ragged's graph cost is ~zero
Aug 2, 2026
3f8e740
[None][fix] Do not fit ragged buckets against rows that will not exist
Aug 2, 2026
d2c19de
[None][fix] Key ragged graphs on the agreed bucket, not a re-derived sum
Aug 3, 2026
6a6789a
[None][doc] Record the P0 outcome: what holds, what was fixed, what b…
Aug 3, 2026
fc7bdb4
[None][doc] Scope the P0 results to B300; call out what will not tran…
Aug 3, 2026
46fc7d1
[None][doc] Reconcile the docs with what was actually measured
Aug 3, 2026
9597f64
[None][doc] Mark the superseded claims inline, not just in the banner
Aug 3, 2026
bb8198d
[None][chore] Remove the uniform tier-ladder verify path
Aug 3, 2026
95484a2
[None][doc] Record that the uniform tier ladder was removed, not just…
Aug 3, 2026
0f94c04
[None][feat] Implement the cap-accept ragged verify mode
Aug 3, 2026
9acabe5
[None][fix] Cap cap-accept inside acceptance, not on the host afterwards
Aug 3, 2026
8f82517
[None][fix] Give the CUDA-graph padding dummy a verify cap
Aug 3, 2026
faf2c60
[None][feat] Record cap-accept's acceptance loss per request
Aug 3, 2026
8d3fc55
[None][fix] Build the CUDA-graph capture set from the mode, not the c…
Aug 3, 2026
1d51566
[None][fix] Capture one draft length, and make the planner's counters…
Aug 3, 2026
7f13404
[None][fix] Repair the tests the uniform-path removal broke
Aug 3, 2026
5711155
[None][fix] Publish the ragged bucket during CUDA-graph capture
Aug 3, 2026
79150aa
[None][fix] Gather whether row padding will happen instead of predict…
Aug 3, 2026
b095804
[None][fix] Decline the ragged fit when no rank can graph the step
Aug 3, 2026
f033e3c
[None][fix] Run ragged without a bucket on steps that have no graph
Aug 3, 2026
59e2d47
[None][fix] Clear the ragged pad window on steps that skip the bucket…
Aug 3, 2026
4f81cc5
[None][fix] Gate the eager-ragged path off until its IMA is understood
Aug 4, 2026
cdc4538
[None][chore] Name the token-major row-map staleness instead of faulting
Aug 4, 2026
d36c9b4
[None][doc] Hand off the ragged-verify IMA, including where I had it …
Aug 4, 2026
6a59b01
[None][fix] Derive a ragged graph key only when every request carries…
Aug 5, 2026
35a1ac4
[None][fix] Re-enable ragged verification on graph-less steps
Aug 5, 2026
74f1a82
[None][fix] Stage KVCacheManagerV2 block-offset copies through pinned…
Aug 5, 2026
c7e6d78
[None][fix] Harden DSA metadata against overlap WAR and layout drift
Aug 5, 2026
5c38441
[None][fix] Bound the overlap previous-batch staging inputs
Aug 5, 2026
648d601
[None][chore] Let a diagnostic env override the hang-detection timeout
Aug 5, 2026
226b1ff
[None][doc] Close out the ragged-verify IMA investigation
Aug 5, 2026
72dd803
[None][fix] Interpolate the SPS cost table between breakpoints
lancelly Aug 5, 2026
c117be8
[None][feat] Calibrate DSpark confidence and measure the planner's in…
lancelly Aug 5, 2026
50675cb
[None][fix] Make the ragged fit's consistency checks able to fail
lancelly Aug 5, 2026
0b52443
[None][feat] Pin the DSpark verify length at runtime
lancelly Aug 5, 2026
fab6291
[None][chore] Measure the SPS table against the deployment, not a reb…
lancelly Aug 5, 2026
34a4b4b
[None][doc] Review the 2026-08-04 follow-up commits: 34 confirmed fin…
Aug 5, 2026
8a1a604
[None][fix] Address the 2026-08-04 review: repair STS pairing end to end
lancelly Aug 5, 2026
5910c9f
[None][chore] Slim the PR: comments, getattr fallbacks, env vars, tes…
lancelly Aug 5, 2026
3afeb5e
[None][chore] Deep-slim the DSpark tests; drop the process docs
lancelly Aug 5, 2026
7327a93
[None][chore] Test only what ships: drop tool and observability test …
lancelly Aug 5, 2026
b7e091d
[None][fix] Choose the ragged bucket every rank can decompose
lancelly Aug 5, 2026
22f9330
[None][fix] Server sweeps under attention DP promise no bs grid
lancelly Aug 5, 2026
5364482
[None][chore] Strip war-story comments, residual getattr, and debug e…
lancelly Aug 5, 2026
59cdc06
[None][fix] Remove the debug harnesses that outlived their investigat…
lancelly Aug 5, 2026
1b13535
[None][feat] Profile the SPS table on the live ragged path (budget-fr…
lancelly Aug 6, 2026
08e1eea
[None][feat] Device-side fill_bucket and row-map construction (captur…
lancelly Aug 6, 2026
116bb80
[None][feat] Assemble the device window-selection prologue
lancelly Aug 6, 2026
eac5f72
[None][feat] Device-side window selection: fresh ranking, lag-2 capacity
lancelly Aug 7, 2026
9d38586
[None][fix] cap-accept: never bake a capless capture into the graph
lancelly Aug 7, 2026
63dcc7d
[None][feat] Budget-override scheduling for cap-accept differentials
lancelly Aug 7, 2026
f5b1ade
[None][feat] Profiler: 128-step warmup default and --engine-tiers
lancelly Aug 7, 2026
19502c8
[None][fix] Device-window kv_lens delta counts the window twice
lancelly Aug 8, 2026
621c82c
[None][doc] Device-window corruption investigation log (living doc)
lancelly Aug 8, 2026
e2acaf2
[None][chore] Read-only invariant audit for the device-window prologue
lancelly Aug 8, 2026
57e9d56
[None][fix] Device windows: compressor gen-token counts must follow t…
lancelly Aug 8, 2026
20686d3
[None][doc] Root-cause log for the device-window corruption + rowdiv …
lancelly Aug 8, 2026
4cb6113
[None][doc] Device-window fix validated: both census verdicts clean
lancelly Aug 8, 2026
f40804f
[None][doc] GSM8K at 1024 global concurrency: device windows 96.323 v…
lancelly Aug 8, 2026
0b9c9d4
[None][doc] Honest three-arm throughput closes #30: no device gain wi…
lancelly Aug 8, 2026
fdfa9a4
[None][doc] Quantitative decomposition of why dynamic trim shows no g…
lancelly Aug 8, 2026
a26a319
[None][doc] Cross-stack check: SGLang gains +2.6..+7.7% on our worklo…
lancelly Aug 9, 2026
f2b4a1d
[None][doc] DEP4 attempt infeasible (Pro OOM at tp4); regime question…
lancelly Aug 9, 2026
9f12c06
[None][doc] Exchange-rate math closes: prime suspect is batch fragmen…
lancelly Aug 9, 2026
4fe403b
[None][doc] Cap-accept verdict (#20): only 6.2%/16.1% of trimmed toke…
lancelly Aug 9, 2026
327b9c0
[None][doc] Parity verdict: dynamic trim is a compensation mechanism …
lancelly Aug 9, 2026
420cc4e
[None][doc] Iter-log ground truth overturns flat-theta: short-window …
lancelly Aug 9, 2026
48a4f1d
[None][doc] nsys report-loss root cause: missing fork tracing; v6 flags
lancelly Aug 10, 2026
34ddf04
[None][doc] nsys v6 verdict (2026.2.1 injection failure) and v7 recip…
lancelly Aug 10, 2026
ceae4e2
[None][doc] nsys v7 reports landed; preliminary kernel diff points at…
lancelly Aug 10, 2026
b356755
[None][doc] #32 verdict: short-window penalty is a host sync chain in…
lancelly Aug 10, 2026
b87ea28
[None][perf] Double-buffer pinned staging: short-window prepare no lo…
lancelly Aug 10, 2026
24bd23c
[None][doc] #32 fix validated: pin3 53.7->42.2ms, theta positive again
lancelly Aug 10, 2026
81367a4
[None][doc] #32 closed: FRAC0.4 mixed-window arm confirms the fix (42…
lancelly Aug 10, 2026
5dfca9b
[None][doc] Post-fix retest first batch: forced trim flips to +5.3/+7…
lancelly Aug 10, 2026
8be4662
[None][doc] Retest final: arena bs1024 +1.5% (n=10); table re-collect…
lancelly Aug 10, 2026
e672398
[None][doc] Post-fix cost table: theta monotone with real mass, match…
lancelly Aug 10, 2026
7333a13
[None][doc] #33 final: scheduled trim positive on all four cells (+6.…
lancelly Aug 10, 2026
98e385a
[None][doc] #31 repro + elimination chain + block-granularity token-b…
lancelly Aug 10, 2026
10b6aad
[None][doc] #31 experiment void notice: zombie serves on 2-node alloc…
lancelly Aug 10, 2026
27733a7
[None][doc] #31 clean elimination chain: scheduler picks ~60 of 128 a…
lancelly Aug 10, 2026
0427007
[None][doc] #31 bisection lands: cap = max_batch_size/2; maxbs=256 re…
lancelly Aug 10, 2026
40bd8f6
[None][doc] Post-fix Pro table: monotone theta, w4 anomaly and stairc…
lancelly Aug 10, 2026
ad169e9
[None][doc] FINAL VERDICT: Pro@DEP8 confidence scheduling +5.9~+24.7%…
lancelly Aug 10, 2026
722852c
[None][doc] #34 breakthrough: cap is not spec-specific; V2 scheduler …
lancelly Aug 11, 2026
efb283d
[None][doc] #34 root cause: windowed pool sized 1 block/request, runt…
lancelly Aug 11, 2026
6e65c54
[None][test] DSpark hw-agnostic unit tests: planner parity, cost inte…
lancelly Aug 11, 2026
493996f
[None][test] DSpark verify-len pin, planner trim, and forced-acceptan…
lancelly Aug 11, 2026
25f279e
[None][test] Ragged verify config validation test
lancelly Aug 11, 2026
8874ddf
[None][doc] #34 option C validated: explicit max_seq_len unpins the w…
lancelly Aug 11, 2026
d7f3c40
[None][doc] #34 experiment loop closed: 2x2 quadrants + explicit max_…
lancelly Aug 11, 2026
3136626
[None][chore] Strip debug scaffolding and dev-history comments from t…
lancelly Aug 11, 2026
52fc0e7
[None][chore] Cleanup remainder: HOST_STEEP bisector, dead predicates…
lancelly Aug 11, 2026
11bf02a
[None][chore] Trim branch-relative narration from planner-trims test …
lancelly Aug 11, 2026
c943884
[None][doc] GSM8K regression passes on the ragged path with the post-…
lancelly Aug 11, 2026
27191b6
[None][chore] Consolidate DSpark unit tests and simplify defensive ac…
lancelly Aug 11, 2026
0d00065
[None][doc] Alignment run on their workload: no gain for scheduled tr…
lancelly Aug 11, 2026
9c49301
[None][doc] Disagg campaign: environment-trap matrix (pmix, NIXL tran…
lancelly Aug 11, 2026
66c227f
[None][doc] Deployment rule for the maxbs/2 windowed-pool cap (explic…
lancelly Aug 11, 2026
3bf9348
[None][doc] Benchmark config: pin bs by client in-flight count; drop …
lancelly Aug 11, 2026
2391b20
[None][doc] Disagg bs pinning: moderate client oversubscription (2-4x…
lancelly Aug 11, 2026
7220462
[None][doc] Dataset provenance for the three benchmark workloads (poe…
lancelly Aug 11, 2026
9af9e78
[None][doc] Disagg independent-repro campaign (laliao): own-harness r…
lancelly Aug 11, 2026
9c5d203
[None][doc] Provide verbatim poetry prompt and bench client for indep…
lancelly Aug 11, 2026
6ac04b5
[None][doc] Disagg repro launched (poetry line); request throughput_1…
lancelly Aug 11, 2026
7374e65
[None][feat] Experimental mixed-step trim guard (TLLM_DSPARK_SKIP_MIX…
lancelly Aug 11, 2026
348b01e
[None][doc] Same-node confirm locks mixed-step verdict (+7-8pp recove…
lancelly Aug 11, 2026
99ab172
[None][doc] First valid disagg cell: pure-gen at shallow bs still -8.…
lancelly Aug 11, 2026
d835dd7
[None][doc] Independent agg verdict: frac04 mechanical trim negative …
lancelly Aug 11, 2026
eadd65d
[None][doc] v4 measured table + mixed-step gate turn agg t128 from -1…
lancelly Aug 11, 2026
b20ce02
[None][doc] Disagg bring-up gates pass (77k full-batch steps, transfe…
lancelly Aug 11, 2026
1a48727
[None][doc] Publish exact profinal arm yamls and postfix table for ke…
lancelly Aug 12, 2026
6fce248
[None][doc] Agg replication closed: client-semantics conviction, unif…
lancelly Aug 12, 2026
0411ae1
[None][doc] Reply: arena burst semantics for protocol alignment; disa…
lancelly Aug 12, 2026
2754700
[None][doc] Deep-bs disagg verdict: throughput_1k turns positive (+4.…
lancelly Aug 12, 2026
b3a116f
[None][doc] Quantization economics verified (fp8 vs nvfp4 same-node A…
lancelly Aug 12, 2026
1c62fe0
[None][doc] 256-deep disagg verdict: +7.0/+15.6% both arm orders; v5 …
lancelly Aug 12, 2026
431925a
[None][doc] AA slo20 campaign: ragged path validated in production sh…
lancelly Aug 13, 2026
7c8cea5
[None][doc] AA slo20 final verdict: scheduled +6.7%/+7.4% median (n=3…
lancelly Aug 13, 2026
5c418d4
[None][doc] slo20-true campaign: v2 dangling-rawref convicted on tran…
lancelly Aug 16, 2026
8f394a8
[None][doc] slo20-true four-arm final: static DL cuts hurt SLO (-8~-1…
lancelly Aug 16, 2026
05916a8
[None][doc] slo20-shape table re-collected: 78% of step is untrimmabl…
lancelly Aug 18, 2026
b853378
[None][doc] sched x re-collected slo20 table: prediction hit (trim 0.…
lancelly Aug 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions cpp/tensorrt_llm/kernels/IndexerTopK.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,18 @@ int computeIndexerTopKDecodeBlocksPerRow(int numRows, int numColumns, int splitW
/// - Insertion sort (N < kSortingAlgorithmThreshold)
/// - Radix sort (kSortingAlgorithmThreshold ≤ N < splitWork)
/// - Radix split-work (N ≥ splitWork — uses outLogitsAux / outIndicesAux)
///
/// @param rowKvLens optional [numRows] per-row causal KV extent, in uncompressed
/// token space. Non-null selects the ragged layout: rows no longer map to
/// requests by `rowIdx / next_n`, so the extent every row may attend to is
/// supplied directly instead of being reconstructed from `next_n`. Null keeps
/// the uniform arithmetic, bit-identical to before. Mutually exclusive with
/// `preIdx` (GVR's hint is request-indexed through `next_n` as well).
void invokeIndexerTopKDecode(float const* logits, int const* seqLens, int* indices, float* outLogitsAux,
int* outIndicesAux, int const splitWorkThreshold, int const numRows, int const numColumns, int const stride0,
int const stride1, int const next_n, int const topK = 2048, int const* preIdx = nullptr, int const preIdxStride = 0,
int const preIdxCount = 0, float* heuristicScratch = nullptr, int const compressRatio = 1,
cudaStream_t const stream = 0);
int const* rowKvLens = nullptr, cudaStream_t const stream = 0);

/// bf16 indexer TopK decode — same dispatch axes as the fp32 entry, except
/// kBsL2 uses sizeof(__nv_bfloat16) bytes/elem (L2 footprint is half) and
Expand All @@ -59,13 +66,14 @@ void invokeIndexerTopKDecode(__nv_bfloat16 const* logits, int const* seqLens, in
int const splitWorkThreshold, int const numRows, int const numColumns, int const stride0, int const stride1,
int const next_n, int const topK = 2048, int const* preIdx = nullptr, int const preIdxStride = 0,
int const preIdxCount = 0, __nv_bfloat16* heuristicScratch = nullptr, int const compressRatio = 1,
cudaStream_t const stream = 0);
int const* rowKvLens = nullptr, cudaStream_t const stream = 0);

/// fp16 indexer TopK decode — see bf16 overload for dispatcher contract.
void invokeIndexerTopKDecode(__half const* logits, int const* seqLens, int* indices, int const splitWorkThreshold,
int const numRows, int const numColumns, int const stride0, int const stride1, int const next_n,
int const topK = 2048, int const* preIdx = nullptr, int const preIdxStride = 0, int const preIdxCount = 0,
__half* heuristicScratch = nullptr, int const compressRatio = 1, cudaStream_t const stream = 0);
__half* heuristicScratch = nullptr, int const compressRatio = 1, int const* rowKvLens = nullptr,
cudaStream_t const stream = 0);

void invokeIndexerTopKPrefill(float const* logits, int const* rowStarts, int const* rowEnds, int* indices,
int const numRows, int const numColumns, int const stride0, int const stride1, int const topK = 2048,
Expand Down
21 changes: 16 additions & 5 deletions cpp/tensorrt_llm/kernels/compressorKernels/compressorKernels.cu
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ __global__ void pagedKvCompressKernel(void const* __restrict__ kv_score_raw, flo
void* __restrict__ paged_kv_raw, void* __restrict__ paged_score_raw, int32_t const* __restrict__ block_table_kv,
int32_t const* __restrict__ block_table_score, void* __restrict__ output_raw, int32_t const* __restrict__ kv_lens,
int32_t const* __restrict__ cu_seq_lens, int32_t const* __restrict__ cu_kv_comp, int page_size, int max_blocks,
int out_elem_bytes)
int out_elem_bytes, int32_t const* __restrict__ new_tokens_per_seq = nullptr)
{
using KvScoreElemT = typename std::conditional<KV_SCORE_ELEM_BYTES == 2, __nv_bfloat16, float>::type;
using StateElemT = typename std::conditional<STATE_ELEM_BYTES == 2, __nv_bfloat16, float>::type;
Expand Down Expand Up @@ -337,7 +337,16 @@ __global__ void pagedKvCompressKernel(void const* __restrict__ kv_score_raw, flo
int const eff_tid = head_blk * NTHRD_INNER + tid;

int const kv_len = kv_lens[batch_idx];
int const sp = kv_len - NEXT_N;
// How many tokens this request appended this step. Uniform batches append
// NEXT_N each, which is what the template bound encodes. Under DSpark's
// ragged verification each request appends its own window instead, so the
// count is read per request and NEXT_N degrades to a compile-time *upper*
// bound -- which is all the loops below need it to be, because both are
// already guarded (Phase 1 by token_idx < kv_len, Phase 3 by
// num_compressions). Keeping NEXT_N as the bound is what preserves the
// full unroll on the uniform path.
int const nn = (new_tokens_per_seq != nullptr) ? new_tokens_per_seq[batch_idx] : NEXT_N;
int const sp = kv_len - nn;
int const in_off = cu_seq_lens[batch_idx];
int const out_off = cu_kv_comp[batch_idx];
int64_t const page_sd = static_cast<int64_t>(page_size) * STATE_DIM;
Expand Down Expand Up @@ -413,7 +422,7 @@ __global__ void pagedKvCompressKernel(void const* __restrict__ kv_score_raw, flo
// ================================================================
// Phase 2: Count how many complete compression windows finished.
// ================================================================
int last_token_idx = sp + NEXT_N - 1;
int last_token_idx = sp + nn - 1;
int num_compressions = (last_token_idx + 1) / COMPRESS_RATIO - sp / COMPRESS_RATIO;

// ================================================================
Expand Down Expand Up @@ -663,7 +672,8 @@ __global__ void pagedKvCompressKernel(void const* __restrict__ kv_score_raw, flo
// Generate explicit template instantiations.
#define INST_DECODE(HD, KV_EB, STATE_EB, CR, NN, NRW) \
template __global__ void pagedKvCompressKernel<HD, KV_EB, STATE_EB, CR, NN, NRW>(void const*, float const*, void*, \
void*, int32_t const*, int32_t const*, void*, int32_t const*, int32_t const*, int32_t const*, int, int, int);
void*, int32_t const*, int32_t const*, void*, int32_t const*, int32_t const*, int32_t const*, int, int, int, \
int32_t const*);
FOREACH_DECODE_CONFIG(INST_DECODE)
#undef INST_DECODE

Expand All @@ -680,6 +690,7 @@ void pagedKvCompressLaunch(void const* kv_score, float const* ape, void* paged_k
int32_t const* block_table_kv, int32_t const* block_table_score, void* output, int32_t const* kv_lens,
int32_t const* cu_seq_lens, int32_t const* cu_kv_comp, int batch_size, int page_size, int max_blocks, int head_dim,
int compress_ratio, int next_n, int kv_score_elem_bytes, int state_elem_bytes, int out_elem_bytes,
int32_t const* new_tokens_per_seq,
cudaStream_t stream)
{
TLLM_CHECK_WITH_INFO(
Expand Down Expand Up @@ -731,7 +742,7 @@ void pagedKvCompressLaunch(void const* kv_score, float const* ape, void* paged_k
{ \
pagedKvCompressKernel<HD, KV_EB, STATE_EB, CR, NN, NRW><<<grid, nthreads, smem_bytes, stream>>>(kv_score, ape, \
paged_kv, paged_score, block_table_kv, block_table_score, output, kv_lens, cu_seq_lens, cu_kv_comp, \
page_size, max_blocks, out_elem_bytes); \
page_size, max_blocks, out_elem_bytes, new_tokens_per_seq); \
return; \
}
FOREACH_DECODE_CONFIG(TRY_LAUNCH)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ void pagedKvCompressLaunch(void const* kv_score, // [m, 2*state_dim] (bf16 or f
int kv_score_elem_bytes, // bytes per element for kv_score (2=bf16, 4=fp32)
int state_elem_bytes, // bytes per element for paged state (2=bf16, 4=fp32)
int out_elem_bytes, // bytes per element for output
int32_t const* new_tokens_per_seq, // [bsz] or nullptr; per-request tokens appended this
// step. nullptr means every request appended next_n
// (the uniform case); non-null makes next_n an upper
// bound only, for DSpark ragged verification.
cudaStream_t stream);

// Prefill kernel: bulk compression with per-token gather/scatter + state update.
Expand Down
64 changes: 50 additions & 14 deletions cpp/tensorrt_llm/kernels/indexerTopK.cu
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,8 @@ template <int kNumThreadsPerBlock, bool useRadixSort, bool multipleBlocksPerRow
typename InputT = float>
static __global__ __launch_bounds__(kNumThreadsPerBlock) void topKPerRowDecode(InputT const* logits, int const* seqLens,
int* outIndices, int stride0, int stride1, int const topK, int next_n, int compressRatio,
float* outLogits = nullptr, int const numBlocksToMerge = 0, int const* indices = nullptr)
float* outLogits = nullptr, int const numBlocksToMerge = 0, int const* indices = nullptr,
int const* rowKvLens = nullptr)
{
#if (defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 900))
cudaGridDependencySynchronize();
Expand All @@ -664,8 +665,27 @@ static __global__ __launch_bounds__(kNumThreadsPerBlock) void topKPerRowDecode(I

// The range of logits within the row.
int rowStart = 0;
int seq_len = seqLens[rowIdx / next_n];
int actual_kv_len = seq_len - next_n + (rowIdx % next_n) + 1;
// Two ways to learn how far back this query row may attend.
//
// Uniform (rowKvLens == nullptr): every request contributes exactly next_n
// rows, so the request index and the row's offset inside its verify window
// both fall out of integer division, and the causal extent is the request's
// sequence length walked back to this offset.
//
// Ragged (rowKvLens != nullptr): requests contribute different numbers of
// rows, so neither rowIdx / next_n nor rowIdx % next_n means anything. The
// caller precomputes the extent per row -- it is the only quantity this
// kernel ever derived from next_n, which is why one array is enough.
int actual_kv_len;
if (rowKvLens != nullptr)
{
actual_kv_len = rowKvLens[rowIdx];
}
else
{
int seq_len = seqLens[rowIdx / next_n];
actual_kv_len = seq_len - next_n + (rowIdx % next_n) + 1;
}
int rowEnd = actual_kv_len / compressRatio;

// Local pointers to this block
Expand Down Expand Up @@ -890,9 +910,16 @@ int computeIndexerTopKDecodeBlocksPerRow(int numRows, int numColumns, int splitW
void invokeIndexerTopKDecode(float const* logits, int const* seqLens, int* indices, float* outLogitsAux,
int* outIndicesAux, int const splitWorkThreshold, int const numRows, int const numColumns, int const stride0,
int const stride1, int const next_n, int const topK, int const* preIdx, int const preIdxStride,
int const preIdxCount, float* heuristicScratch, int const compressRatio, cudaStream_t const stream)
int const preIdxCount, float* heuristicScratch, int const compressRatio, int const* rowKvLens,
cudaStream_t const stream)
{
constexpr int kNumThreadsPerBlock = 512;
// GVR consumes previous-step Top-K hints indexed by request, which it also
// recovers from next_n. Ragged batches therefore cannot take that path; the
// caller is expected to have disabled the hint, and this makes the
// requirement explicit rather than letting a stale preIdx through.
TLLM_CHECK_WITH_INFO(rowKvLens == nullptr || preIdx == nullptr,
"indexer TopK decode: ragged rowKvLens is incompatible with the GVR preIdx hint");
int const effectiveSplitWorkThreshold = splitWorkThreshold > 0 ? splitWorkThreshold : kDefaultSplitWorkThreshold;

// ========================================================================
Expand Down Expand Up @@ -1016,7 +1043,7 @@ void invokeIndexerTopKDecode(float const* logits, int const* seqLens, int* indic
config.attrs = attrs;

cudaLaunchKernelEx(&config, kernel_instance, logits, seqLens, indices, stride0, stride1, topK, next_n,
compressRatio, nullptr, 0, nullptr);
compressRatio, nullptr, 0, nullptr, rowKvLens);
}
else
{
Expand All @@ -1031,7 +1058,7 @@ void invokeIndexerTopKDecode(float const* logits, int const* seqLens, int* indic
config_part1.attrs = attrs;

cudaLaunchKernelEx(&config_part1, kernel_instance_part1, logits, seqLens, outIndicesAux, stride0, stride1, topK,
next_n, compressRatio, outLogitsAux, 0, nullptr);
next_n, compressRatio, outLogitsAux, 0, nullptr, rowKvLens);

constexpr int kNumThreadsPerBlockMerge = 1024;
auto* kernel_instance_part2 = &topKPerRowDecode<kNumThreadsPerBlockMerge, true, false, true>;
Expand All @@ -1043,8 +1070,12 @@ void invokeIndexerTopKDecode(float const* logits, int const* seqLens, int* indic
config_part2.numAttrs = 1;
config_part2.attrs = attrs;

// The merge pass overrides rowEnd with numBlocksToMerge * topK, so the
// extent is unused -- but rowKvLens still has to be forwarded, because
// otherwise the uniform branch would index seqLens by rowIdx / next_n,
// and on a ragged batch next_n is not a divisor of the row count.
cudaLaunchKernelEx(&config_part2, kernel_instance_part2, outLogitsAux, seqLens, indices, blocksPerRow * topK, 1,
topK, next_n, 1, nullptr, blocksPerRow, outIndicesAux);
topK, next_n, 1, nullptr, blocksPerRow, outIndicesAux, rowKvLens);
}
sync_check_cuda_error(stream);
}
Expand Down Expand Up @@ -1079,10 +1110,14 @@ template <typename InputT>
void invokeIndexerTopKDecodeDtype(InputT const* logits, int const* seqLens, int* indices, int const splitWorkThreshold,
int const numRows, int const numColumns, int const stride0, int const stride1, int const next_n, int const topK,
int const* preIdx, int const preIdxStride, int const preIdxCount, InputT* heuristicScratch, int const compressRatio,
cudaStream_t const stream)
int const* rowKvLens, cudaStream_t const stream)
{
static_assert(std::is_same_v<InputT, __nv_bfloat16> || std::is_same_v<InputT, __half>,
"invokeIndexerTopKDecodeDtype is for bf16/fp16 only");
// See the fp32 entry: GVR's hint is request-indexed via next_n, so it and a
// ragged row map cannot both be live.
TLLM_CHECK_WITH_INFO(rowKvLens == nullptr || preIdx == nullptr,
"indexer TopK decode: ragged rowKvLens is incompatible with the GVR preIdx hint");

constexpr int kNumThreadsPerBlock = 512;
int const effectiveSplitWorkThreshold = splitWorkThreshold > 0 ? splitWorkThreshold : kDefaultSplitWorkThreshold;
Expand Down Expand Up @@ -1123,7 +1158,7 @@ void invokeIndexerTopKDecodeDtype(InputT const* logits, int const* seqLens, int*
config.attrs = attrs;

cudaLaunchKernelEx(&config, kernel_instance, logits, seqLens, indices, stride0, stride1, topK, next_n,
compressRatio, nullptr, 0, nullptr);
compressRatio, nullptr, 0, nullptr, rowKvLens);
}
else if (numColumns < effectiveSplitWorkThreshold)
{
Expand All @@ -1143,7 +1178,7 @@ void invokeIndexerTopKDecodeDtype(InputT const* logits, int const* seqLens, int*
config.attrs = attrs;

cudaLaunchKernelEx(&config, kernel_instance, logits, seqLens, indices, stride0, stride1, topK, next_n,
compressRatio, nullptr, 0, nullptr);
compressRatio, nullptr, 0, nullptr, rowKvLens);
}
else
{
Expand All @@ -1162,19 +1197,20 @@ void invokeIndexerTopKDecodeDtype(InputT const* logits, int const* seqLens, int*
void invokeIndexerTopKDecode(__nv_bfloat16 const* logits, int const* seqLens, int* indices,
int const splitWorkThreshold, int const numRows, int const numColumns, int const stride0, int const stride1,
int const next_n, int const topK, int const* preIdx, int const preIdxStride, int const preIdxCount,
__nv_bfloat16* heuristicScratch, int const compressRatio, cudaStream_t const stream)
__nv_bfloat16* heuristicScratch, int const compressRatio, int const* rowKvLens, cudaStream_t const stream)
{
invokeIndexerTopKDecodeDtype<__nv_bfloat16>(logits, seqLens, indices, splitWorkThreshold, numRows, numColumns,
stride0, stride1, next_n, topK, preIdx, preIdxStride, preIdxCount, heuristicScratch, compressRatio, stream);
stride0, stride1, next_n, topK, preIdx, preIdxStride, preIdxCount, heuristicScratch, compressRatio, rowKvLens,
stream);
}

void invokeIndexerTopKDecode(__half const* logits, int const* seqLens, int* indices, int const splitWorkThreshold,
int const numRows, int const numColumns, int const stride0, int const stride1, int const next_n, int const topK,
int const* preIdx, int const preIdxStride, int const preIdxCount, __half* heuristicScratch, int const compressRatio,
cudaStream_t const stream)
int const* rowKvLens, cudaStream_t const stream)
{
invokeIndexerTopKDecodeDtype<__half>(logits, seqLens, indices, splitWorkThreshold, numRows, numColumns, stride0,
stride1, next_n, topK, preIdx, preIdxStride, preIdxCount, heuristicScratch, compressRatio, stream);
stride1, next_n, topK, preIdx, preIdxStride, preIdxCount, heuristicScratch, compressRatio, rowKvLens, stream);
}

void invokeIndexerTopKPrefill(float const* logits, int const* rowStarts, int const* rowEnds, int* indices,
Expand Down
Loading