@@ -28,6 +28,7 @@ __global__ void PrefixSumKernel(int64_t *ids_remove_padding,
2828 const int max_seq_len,
2929 const int64_t *draft_tokens,
3030 const int *seq_lens_encoder,
31+ const int *seq_lens_decoder,
3132 const int max_draft_tokens_per_batch) {
3233 const int bi = blockIdx .x ;
3334 const int tid = threadIdx .x ;
@@ -39,32 +40,47 @@ __global__ void PrefixSumKernel(int64_t *ids_remove_padding,
3940 const int lane_id = threadIdx .x % 32 ;
4041#endif
4142
42- int cum_seq_len = 0 ;
43+ // Independent q/k prefix sums:
44+ // cu_seqlens_q = Σ seq_lens[j] (new tokens only, for Q/varlen indexing)
45+ // cu_seqlens_k = Σ (seq_lens[j] + seq_lens_decoder[j]) (cached + new, for
46+ // K/FA)
47+ // When seq_lens_decoder == nullptr, cu_seqlens_k degenerates to cu_seqlens_q.
48+ int cum_seq_len_q = 0 ;
49+ int cum_seq_len_k = 0 ;
4350
44- // compute sum of seq_lens[0,1,2,...,bi]
4551 for (int i = lane_id; i < bi + 1 ; i += WARP_SIZE ) {
46- cum_seq_len += seq_lens[i];
52+ const int q_inc = seq_lens[i];
53+ const int k_inc =
54+ q_inc + (seq_lens_decoder != nullptr ? seq_lens_decoder[i] : 0 );
55+ cum_seq_len_q += q_inc;
56+ cum_seq_len_k += k_inc;
4757 }
4858
4959 for (int offset = 1 ; offset < WARP_SIZE ; offset <<= 1 ) {
50- const int tmp = __shfl_up_sync (0xffffffff , cum_seq_len, offset);
51- if (lane_id >= offset) cum_seq_len += tmp;
60+ const int tmp_q = __shfl_up_sync (0xffffffff , cum_seq_len_q, offset);
61+ const int tmp_k = __shfl_up_sync (0xffffffff , cum_seq_len_k, offset);
62+ if (lane_id >= offset) {
63+ cum_seq_len_q += tmp_q;
64+ cum_seq_len_k += tmp_k;
65+ }
5266 }
5367
54- cum_seq_len = __shfl_sync (0xffffffff , cum_seq_len, WARP_SIZE - 1 );
68+ cum_seq_len_q = __shfl_sync (0xffffffff , cum_seq_len_q, WARP_SIZE - 1 );
69+ cum_seq_len_k = __shfl_sync (0xffffffff , cum_seq_len_k, WARP_SIZE - 1 );
5570
5671 if (tid == 0 ) {
57- cu_seqlens_q[bi + 1 ] = cum_seq_len ;
58- cu_seqlens_k[bi + 1 ] = cum_seq_len ;
72+ cu_seqlens_q[bi + 1 ] = cum_seq_len_q ;
73+ cu_seqlens_k[bi + 1 ] = cum_seq_len_k ;
5974 }
6075
6176 if (bi == 0 && tid == 0 ) {
6277 cu_seqlens_q[0 ] = 0 ;
6378 cu_seqlens_k[0 ] = 0 ;
6479 }
6580
81+ // Q-side token scatter uses cum_seq_len_q (new-tokens-only layout).
6682 for (int i = tid; i < seq_lens[bi]; i += blockDim .x ) {
67- const int tgt_seq_id = cum_seq_len - seq_lens[bi] + i;
83+ const int tgt_seq_id = cum_seq_len_q - seq_lens[bi] + i;
6884 if (max_draft_tokens_per_batch > 0 && seq_lens_encoder[bi] <= 0 ) {
6985 // speculative decoding
7086 const int src_seq_id = bi * max_draft_tokens_per_batch + i;
@@ -84,6 +100,7 @@ std::vector<paddle::Tensor> GetPaddingOffset(
84100 const paddle::Tensor &seq_len,
85101 const paddle::optional<paddle::Tensor> &draft_tokens,
86102 const paddle::optional<paddle::Tensor> &seq_lens_encoder,
103+ const paddle::optional<paddle::Tensor> &seq_lens_decoder,
87104 const int64_t cpu_token_num) {
88105#ifdef PADDLE_WITH_CUSTOM_DEVICE
89106 auto dev_ctx = static_cast <const phi::CustomContext *>(
@@ -131,6 +148,7 @@ std::vector<paddle::Tensor> GetPaddingOffset(
131148 max_seq_len,
132149 draft_tokens ? draft_tokens.get ().data <int64_t >() : nullptr ,
133150 seq_lens_encoder ? seq_lens_encoder.get ().data <int32_t >() : nullptr ,
151+ seq_lens_decoder ? seq_lens_decoder.get ().data <int32_t >() : nullptr ,
134152 max_draft_tokens_per_batch);
135153
136154 return {x_remove_padding, batch_id_per_token, cu_seqlens_q, cu_seqlens_k};
@@ -156,7 +174,8 @@ PD_BUILD_STATIC_OP(get_padding_offset)
156174 .Inputs({" input_ids" ,
157175 " seq_len" ,
158176 paddle::Optional (" draft_tokens" ),
159- paddle::Optional (" seq_lens_encoder" )})
177+ paddle::Optional (" seq_lens_encoder" ),
178+ paddle::Optional (" seq_lens_decoder" )})
160179 .Outputs({" x_remove_padding" ,
161180 " batch_id_per_token" ,
162181 " cu_seqlens_q" ,
0 commit comments