Repository navigation
[None][feat] Kimi K3 on modeling_v2: MXFP4 target, MNNVL and collective decode kernels, DSpark drafter #19991
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
a867199
b79745b
592ea1a
31b6275
18f1edd
0d16d09
706cf2d
f0e7d4c
ea84b23
77be712
87c7e70
52ca9fa
8e852d2
543ebb3
871ef64
8806ae3
32a581a
aaef4b7
a1d336d
e85d7a6
4166788
2b465f6
32d419b
1447397
33d3586
5c193ac
490f289
f85b709
135ab0c
00e4394
ac6e287
147b87d
b7ea3f6
19ef779
428f6f2
fe9eaf5
4bf3512
41b2245
aed1c94
d6613a1
3656bcd
74839d1
4657c20
0da8a02
546e567
a9938c2
54b87a2
459e446
c954d6a
1e6eb67
10fd5cf
c48e85e
2f25c1d
3411d48
b3b4e27
ae6e9a9
b521431
13b26f4
50ac9d6
a0509b3
77a450e
c3ced8d
f39f875
b2a6af4
2e598e1
b12bfad
ce1ae63
f9d32b4
93c0b28
0c9ab14
eda9db2
a0fa306
fd37763
bea6002
0e29964
0cbb559
b83f960
d0c47c2
25fd87a
2c331d5
c95eac1
dc903ae
c05a0c3
44a06db
003f8d0
de2f7e1
04c6f56
fd476e7
3f54e9d
547f6bf
70bb2a3
0778b55
adce84a
cb4a371
2cc72d5
21462e1
ddff9e8
ca4918f
67a3ad5
989766a
347d22f
dc76338
8002879
a0712cb
fa41a16
bbd3d04
d67d88e
b803497
d586d7e
864a430
84dfe86
0d83ef5
9ba3b3d
e4b9968
e69dacd
35433fb
eedff8c
c9d0cd4
0bbf728
bcef591
338f9d0
73a9e90
65ddf59
c53ffc8
3ac75a7
28cfb12
bdadd40
305118f
b395762
9e19e8a
cd21be6
54ff61f
97f7072
4aa7153
b16c3c2
55f0635
4c1439a
c14508c
f5c3ae3
1bc8d8b
b330f1c
06d34b7
3a990dc
4612146
9190f8b
deb3d65
4552c8d
c6cd921
c44c900
edc6351
2a91b19
0fd5a3a
4c8533c
6157fb8
657aa25
d639ec5
bca86ba
47a20a2
145def6
0ed2dfd
23a02c1
b648542
42ff681
6d9951a
6a95a9e
6b07622
ee481ee
856a455
6514585
63aa7a2
83becf9
b646dca
b984e33
a486e00
52a3283
520ae9c
379cdf6
9024a43
1695372
2ede9d6
cdbba03
0202519
40df45e
be9f0e4
8bdeec3
72bb8ca
951048b
1cf3ae6
ae7c7a9
a1fb5ba
44c31f6
78b3e1d
9afa851
fd2bb56
991a6e3
1f94ed5
15d5054
b279e48
d29c672
597e23a
3a51287
daa25a2
f1d74e3
f1e009f
3261a6f
97d8936
46cbb85
1f8cdd7
6b3d878
28d1e2a
6b38abc
ae04264
413ee68
3e46156
425d8ef
14a76b0
cb9aa92
97811d8
7b203f8
7bc9de8
27a60ad
cd4d74c
7487caf
9595d2f
be8488e
3b073dc
423c804
c5b7617
b42b37f
18ea5cb
0f9ee92
45aabf9
b19dcdb
ea00015
407b4da
6f7c142
8144424
c7b667d
996bb14
653a47a
d67d9cd
c60ee69
4c9d1ce
61e4b0c
a43e651
f5d9d73
4dc6f91
8c2cefa
a688df8
a44934d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -336,6 +336,7 @@ struct MnnvlAllReduceKernelParams | |
| uint32_t* bufferFlags; | ||
| bool waitForResults; | ||
| QuantizationSFLayout layout; | ||
| bool earlyTrigger; | ||
| }; | ||
|
|
||
| template <typename PackedType, typename T> | ||
|
|
@@ -590,6 +591,10 @@ __global__ void __launch_bounds__(1024) oneshotAllreduceFusionKernel(MnnvlAllRed | |
| int threadOffset = token * params.tokenDim + packedIdx * kELTS_PER_THREAD; | ||
|
|
||
| cudaGridDependencySynchronize(); | ||
| if (params.earlyTrigger) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even though the changes to these communication kernels only add a single parameter, they could potentially impact all existing models that rely on them. My recommendation is not to make incremental changes to this shared kernel in this PR, but instead copy it over to kimi_k3_vl's own directory to modify it there.
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I agree with the principle in general. For this specific case, I think the existing allreduce kernel shall already supported the PDL, I am not sure why do we need this new parameter? Can existing PDL infra support this? @vsabavat
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 |
||
| { | ||
| cudaTriggerProgrammaticLaunchCompletion(); | ||
| } | ||
| #else | ||
| int packedIdx = blockIdx.y * blockDim.x + threadIdx.x; | ||
| int token = blockIdx.x; | ||
|
|
@@ -843,7 +848,7 @@ void oneshotAllreduceFusionOp(AllReduceFusionParams const& params) | |
| MnnvlAllReduceKernelParams<T> kernelParams{output, residualOut, input, residualIn, gamma, ucPtrs, | ||
| reinterpret_cast<T*>(params.bufferPtrLocal), mcPtr, params.quantOut, params.scaleOut, params.scaleFactor, | ||
| numTokens, tokenDim, params.nRanks, params.rank, static_cast<float>(params.epsilon), params.bufferFlags, | ||
| false, params.layout}; | ||
| false, params.layout, params.earlyTrigger}; | ||
|
|
||
| switch (params.nRanks) | ||
| { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,165 @@ | ||
| /* | ||
| * Copyright (c) 2026, NVIDIA CORPORATION. All rights reserved. | ||
| * | ||
| * Licensed under the Apache License, Version 2.0 (the "License"); | ||
| * you may not use this file except in compliance with the License. | ||
| * You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, software | ||
| * distributed under the License is distributed on an "AS IS" BASIS, | ||
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| * See the License for the specific language governing permissions and | ||
| * limitations under the License. | ||
| */ | ||
|
|
||
| #include "tensorrt_llm/kernels/kimiK3Mnnvl/mnnvlAllGatherKernels.h" | ||
|
|
||
| #include "tensorrt_llm/common/cudaUtils.h" | ||
| #include "tensorrt_llm/common/envUtils.h" | ||
| #include "tensorrt_llm/common/lamportUtils.cuh" | ||
|
|
||
| TRTLLM_NAMESPACE_BEGIN | ||
|
|
||
| namespace kernels::kimiK3Mnnvl | ||
| { | ||
|
|
||
| using tensorrt_llm::common::isLamportDirty; | ||
| using tensorrt_llm::common::LamportFlags; | ||
| using tensorrt_llm::common::loadPackedVolatile; | ||
| using tensorrt_llm::common::VolatilePackedLoad; | ||
|
|
||
| namespace | ||
| { | ||
|
|
||
| constexpr int kThreads = 256; | ||
|
|
||
| // Payload vectors (16 bytes) of one rank's slot for one token: the bf16 part, then the fp32 part. | ||
| __host__ __device__ inline int slotVectors(int bf16Columns, int fp32Columns) | ||
| { | ||
| return bf16Columns / 8 + fp32Columns / 4; | ||
| } | ||
|
|
||
| // No payload word may equal the Lamport sentinel (the fp32 -0.0 word): -0.0 halves of a bf16 | ||
| // pair and -0.0 fp32 words become +0.0. | ||
| __device__ inline uint32_t sanitizeBf16Pair(uint32_t word) | ||
| { | ||
| if ((word & 0xffffu) == 0x8000u) | ||
| { | ||
| word &= 0xffff0000u; | ||
| } | ||
| if ((word >> 16) == 0x8000u) | ||
| { | ||
| word &= 0x0000ffffu; | ||
| } | ||
| return word; | ||
| } | ||
|
|
||
| __device__ inline uint32_t sanitizeFp32(uint32_t word) | ||
| { | ||
| return word == 0x80000000u ? 0u : word; | ||
| } | ||
|
|
||
| __device__ inline uint32_t packBf16Pair(float lo, float hi) | ||
| { | ||
| __nv_bfloat162 const pair = __floats2bfloat162_rn(lo, hi); | ||
| return sanitizeBf16Pair(*reinterpret_cast<uint32_t const*>(&pair)); | ||
| } | ||
|
|
||
| // One CTA per token: broadcast this rank's slot of the token, then poll every rank's slot and | ||
| // scatter it to the outputs. | ||
| __global__ void __launch_bounds__(kThreads) mnnvlAllGatherSplitKernel(AllGatherSplitParams const p) | ||
| { | ||
| #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 900) | ||
| cudaGridDependencySynchronize(); | ||
| // Dependents read the outputs (and the Lamport flags) only after their own wait for this grid. | ||
| cudaTriggerProgrammaticLaunchCompletion(); | ||
| #endif | ||
| int const token = blockIdx.x; | ||
| int const bf16Vectors = p.bf16Columns / 8; | ||
| int const vectors = slotVectors(p.bf16Columns, p.fp32Columns); | ||
| int const inputColumns = p.bf16Columns + p.fp32Columns; | ||
|
|
||
| LamportFlags<float4> flag(p.bufferFlags, 1); | ||
| auto* lamportMcast = reinterpret_cast<uint4*>(flag.getCurLamportBuf(p.multicastPtr, 0)); | ||
| auto* lamportLocal = reinterpret_cast<uint4*>(flag.getCurLamportBuf(p.bufferPtrsDev[p.rank], 0)); | ||
|
|
||
| float const* row = p.input + static_cast<int64_t>(token) * inputColumns; | ||
| for (int v = threadIdx.x; v < vectors; v += blockDim.x) | ||
| { | ||
| uint4 packed; | ||
| if (v < bf16Vectors) | ||
| { | ||
| float4 const a = reinterpret_cast<float4 const*>(row)[2 * v]; | ||
| float4 const b = reinterpret_cast<float4 const*>(row)[2 * v + 1]; | ||
| packed = make_uint4( | ||
| packBf16Pair(a.x, a.y), packBf16Pair(a.z, a.w), packBf16Pair(b.x, b.y), packBf16Pair(b.z, b.w)); | ||
| } | ||
| else | ||
| { | ||
| uint4 const words = reinterpret_cast<uint4 const*>(row + p.bf16Columns)[v - bf16Vectors]; | ||
| packed = make_uint4( | ||
| sanitizeFp32(words.x), sanitizeFp32(words.y), sanitizeFp32(words.z), sanitizeFp32(words.w)); | ||
| } | ||
| lamportMcast[(static_cast<int64_t>(token) * p.nRanks + p.rank) * vectors + v] = packed; | ||
| } | ||
|
|
||
| flag.ctaArrive(); | ||
| flag.clearDirtyLamportBuf(p.bufferPtrsDev[p.rank], -1); | ||
|
|
||
| for (int i = threadIdx.x; i < p.nRanks * vectors; i += blockDim.x) | ||
| { | ||
| int const r = i / vectors; | ||
| int const v = i % vectors; | ||
| VolatilePackedLoad<float4> value; | ||
| do | ||
| { | ||
| value | ||
| = loadPackedVolatile<float4>(&lamportLocal[(static_cast<int64_t>(token) * p.nRanks + r) * vectors + v]); | ||
| } while (isLamportDirty(value)); | ||
| uint4 const words = make_uint4(value.words[0], value.words[1], value.words[2], value.words[3]); | ||
| if (v < bf16Vectors) | ||
| { | ||
| reinterpret_cast<uint4*>( | ||
| p.bf16Output + static_cast<int64_t>(token) * p.nRanks * p.bf16Columns + r * p.bf16Columns)[v] | ||
| = words; | ||
| } | ||
| else | ||
| { | ||
| reinterpret_cast<uint4*>(p.fp32Output + static_cast<int64_t>(token) * p.nRanks * p.fp32Columns | ||
| + r * p.fp32Columns)[v - bf16Vectors] | ||
| = words; | ||
| } | ||
| } | ||
|
|
||
| flag.waitAndUpdate({static_cast<uint32_t>(p.numTokens * p.nRanks * vectors * sizeof(uint4)), 0, 0, 0}); | ||
| } | ||
|
|
||
| } // namespace | ||
|
|
||
| int64_t mnnvlAllGatherSplitFootprint(int numTokens, int bf16Columns, int fp32Columns, int nRanks) | ||
| { | ||
| return static_cast<int64_t>(numTokens) * nRanks * slotVectors(bf16Columns, fp32Columns) * sizeof(uint4); | ||
| } | ||
|
|
||
| void mnnvlAllGatherSplitOp(AllGatherSplitParams const& params) | ||
| { | ||
| TLLM_CHECK_WITH_INFO(params.bf16Columns % 8 == 0 && params.fp32Columns % 4 == 0, | ||
| "[mnnvlAllGatherSplit] needs bf16 columns in multiples of 8 and fp32 columns in multiples of 4"); | ||
| TLLM_CHECK_WITH_INFO(params.numTokens > 0, "[mnnvlAllGatherSplit] needs at least one token"); | ||
| cudaLaunchAttribute attrs[1]; | ||
| attrs[0].id = cudaLaunchAttributeProgrammaticStreamSerialization; | ||
| attrs[0].val.programmaticStreamSerializationAllowed = tensorrt_llm::common::getEnvEnablePDL() ? 1 : 0; | ||
| cudaLaunchConfig_t config{}; | ||
| config.gridDim = dim3(params.numTokens); | ||
| config.blockDim = dim3(kThreads); | ||
| config.stream = params.stream; | ||
| config.attrs = attrs; | ||
| config.numAttrs = 1; | ||
| TLLM_CUDA_CHECK(cudaLaunchKernelEx(&config, mnnvlAllGatherSplitKernel, params)); | ||
| } | ||
|
|
||
| } // namespace kernels::kimiK3Mnnvl | ||
|
|
||
| TRTLLM_NAMESPACE_END |
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For the new kernels, please move them to the kimi directory under modeling_v2 (you can add a csrc/ folder for the C++/CUDA sources). Shared kernels for TP16/TP4 belong in models/kimi_k3_vl, while target-specific kernels should reside in their respective target folders. In short, new ops should be scoped to the level where they take effect rather than dumped into generic modules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The K3 C++ kernels are already isolated under
cpp/tensorrt_llm/kernels/kimiK3Mnnvl/; the remaining sharedearlyTriggeroption is default-off. Moving the sources undermodels/kimi_k3_vl/csrc/would also need explicit build wiring, since the current kernel build discovers them undercpp/.Do you want that model-local C++/CUDA build-layout change as well, or is keeping the K3-specific compiled kernels in
cpp/acceptable while moving the Python ops and CuTe DSL kernels into the K3 family/target directories under modeling_v2?