Skip to content

Commit 6248358

Browse files
chang-wenbinchang-wenbin
andauthored
[Feature] Support MLA chunk-prefill & prefix cache for all MLA Architecture Models (#7727)
* support mla chunk-prefill & prefix_cache * optimized mla chunk prefill * optimized mla chunk prefill * update mla chunk-prefill * support mla chunk-prefill & prefix cache * update mla chunk prefill prefix cache * update tests * update test * optimize triton kernel * update deepseek-v3 modeling --------- Co-authored-by: chang-wenbin <changwenbin@gmail.com>
1 parent af78f05 commit 6248358

11 files changed

Lines changed: 681 additions & 46 deletions

custom_ops/gpu_ops/cpp_extensions.cc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -427,6 +427,7 @@ std::vector<paddle::Tensor> GetPaddingOffset(
427427
const paddle::Tensor& seq_len,
428428
const paddle::optional<paddle::Tensor>& draft_tokens,
429429
const paddle::optional<paddle::Tensor>& seq_lens_encoder,
430+
const paddle::optional<paddle::Tensor>& seq_lens_decoder,
430431
const int64_t token_num_cpu);
431432

432433
void SetValueByFlagsAndIdx(const paddle::Tensor& token_ids_all,

custom_ops/gpu_ops/get_padding_offset.cu

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -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",

custom_ops/gpu_ops/get_position_ids_and_mask_encoder_batch.cu

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,25 @@
1717

1818
__global__ void GetPositionIdsAndMaskEncoderBatchKernel(
1919
const int* seq_lens_encoder, // [bsz] 每个批次的 encoder 长度
20-
const int* seq_lens_decoder, // [bsz] 每个批次的 decoder 长度
20+
const int* seq_lens_decoder, // [bsz] 每个批次的 decoder 长度 (对于 MLA
21+
// prefix cache,这是 cached KV 长度)
2122
const int* seq_lens_this_time,
2223
int* position_ids, // 输出的一维 position_ids
2324
const int bsz) { // 批次大小
2425
// 当前线程索引(每个线程对应一个批次)
2526
int tid = threadIdx.x;
2627
if (tid >= bsz) return;
2728

28-
// 动态计算当前批次的偏移量
29+
// 动态计算当前批次的偏移量。
30+
// 每个 batch 只会贡献 encoder_len 或 seq_lens_this_time 中的一个,
31+
// 而非两者之和(chunked prefill 时 encoder_len > 0 与 decoder_len > 0
32+
// 同时成立,
33+
// 但该 batch 只有 encoder_len 个真实 token)。
2934
int offset = 0;
3035
for (int i = 0; i < tid; i++) {
31-
offset += seq_lens_encoder[i];
32-
if (seq_lens_decoder[i] > 0) {
36+
if (seq_lens_encoder[i] > 0) {
37+
offset += seq_lens_encoder[i];
38+
} else if (seq_lens_decoder[i] > 0) {
3339
offset += seq_lens_this_time[i];
3440
}
3541
}
@@ -39,16 +45,21 @@ __global__ void GetPositionIdsAndMaskEncoderBatchKernel(
3945
int decoder_len = seq_lens_decoder[tid];
4046
int seq_len_this_time = seq_lens_this_time[tid];
4147

42-
// 写入 encoder 的 position_ids
43-
for (int i = 0; i < encoder_len; i++) {
44-
position_ids[offset + i] = i;
45-
}
46-
offset += encoder_len;
47-
48-
// 写入 decoder 的 position_ids
49-
if (decoder_len > 0) {
48+
// For MLA with prefix cache support:
49+
// - Chunked prefill (encoder_len > 0 && decoder_len > 0):
50+
// only writes encoder positions starting at decoder_len (cached length).
51+
// - First-chunk prefill (encoder_len > 0 && decoder_len == 0):
52+
// writes encoder positions starting at 0.
53+
// - Pure decode (encoder_len == 0 && decoder_len > 0):
54+
// writes seq_lens_this_time decode positions starting at decoder_len.
55+
if (encoder_len > 0) {
56+
int start_pos = (decoder_len > 0) ? decoder_len : 0;
57+
for (int i = 0; i < encoder_len; i++) {
58+
position_ids[offset + i] = start_pos + i;
59+
}
60+
} else if (decoder_len > 0) {
5061
for (int i = 0; i < seq_len_this_time; i++) {
51-
position_ids[offset + i] = decoder_len + i; // 使用 decoder 长度本身
62+
position_ids[offset + i] = decoder_len + i;
5263
}
5364
}
5465
}

0 commit comments

Comments
 (0)