[GDN] Improve kkt kernel of CuteDSL prefill backend (#46346)
Signed-off-by: Thien Tran <gau.nernst@yahoo.com.sg>
Thien Tran committed
Jun 30, 2026 at 09:34 UTC
43916891b222c4ebe85e4c1f4da08202373ede30
6 files changed
+554
-474
vllm/cute_utils/__init__.py
+29
-15
@@ -95,40 +95,54 @@ def mma_bf16(
95
return cute.TensorSSA(vec, 4, Float32)
96
97
98
-@dsl_user_op
99
-def _bf16x2_abs(a: Uint32, *, loc=None, ip=None) -> Uint32:
98
+def _bf16x2_unary(asm: str, a: Uint32, *, loc=None, ip=None) -> Uint32:
99
out = llvm.inline_asm(
100
T.i32(),
101
[a.ir_value(loc=loc, ip=ip)],
103
- "abs.bf16x2 $0, $1;",
102
+ f"{asm}.bf16x2 $0, $1;",
103
"=r,r",
104
has_side_effects=False,
105
is_align_stack=False,
106
+ loc=loc,
107
+ ip=ip,
108
)
109
return Uint32(out)
110
111
111
-@dsl_user_op
112
-def _bf16x2_max(a: Uint32, b: Uint32, *, loc=None, ip=None) -> Uint32:
112
+def _bf16x2_binary(asm: str, a: Uint32, b: Uint32, *, loc=None, ip=None) -> Uint32:
113
out = llvm.inline_asm(
114
T.i32(),
115
[a.ir_value(loc=loc, ip=ip), b.ir_value(loc=loc, ip=ip)],
116
- "max.bf16x2 $0, $1, $2;",
116
+ f"{asm}.bf16x2 $0, $1, $2;",
117
"=r,r,r",
118
has_side_effects=False,
119
is_align_stack=False,
120
+ loc=loc,
121
+ ip=ip,
122
)
123
return Uint32(out)
124
125
126
+@dsl_user_op
127
+def _bf16x2_abs(a: Uint32, *, loc=None, ip=None) -> Uint32:
128
+ return _bf16x2_unary("abs", a, loc=loc, ip=ip)
129
+
130
+
131
+@dsl_user_op
132
+def _bf16x2_neg(a: Uint32, *, loc=None, ip=None) -> Uint32:
133
+ return _bf16x2_unary("neg", a, loc=loc, ip=ip)
134
+
135
+
136
+@dsl_user_op
137
+def _bf16x2_max(a: Uint32, b: Uint32, *, loc=None, ip=None) -> Uint32:
138
+ return _bf16x2_binary("max", a, b, loc=loc, ip=ip)
139
+
140
+
141
@dsl_user_op
142
def _bf16x2_mul(a: Uint32, b: Uint32, *, loc=None, ip=None) -> Uint32:
126
- out = llvm.inline_asm(
127
- T.i32(),
128
- [a.ir_value(loc=loc, ip=ip), b.ir_value(loc=loc, ip=ip)],
129
- "mul.rn.bf16x2 $0, $1, $2;",
130
- "=r,r,r",
131
- has_side_effects=False,
132
- is_align_stack=False,
133
- )
134
- return Uint32(out)
143
+ return _bf16x2_binary("mul.rn", a, b, loc=loc, ip=ip)
144
+
145
+
146
+@dsl_user_op
147
+def _bf16x2_sub(a: Uint32, b: Uint32, *, loc=None, ip=None) -> Uint32:
148
+ return _bf16x2_binary("sub.rn", a, b, loc=loc, ip=ip)
vllm/cute_utils/_tcgen05.py
+34
-30
@@ -90,17 +90,18 @@ def mma_f16(
90
loc=None,
91
ip=None,
92
) -> None:
93
- nvvm.tcgen05_mma(
94
- nvvm.Tcgen05MMAKind.F16,
95
- NVVM_CTA_GROUP_MAP[cta_group],
96
- _make_tmem_llvm_ptr(d_tmem, loc=loc, ip=ip),
97
- Uint64(a_desc).ir_value(loc=loc, ip=ip),
98
- Uint64(b_desc).ir_value(loc=loc, ip=ip),
99
- Int32(idesc).ir_value(loc=loc, ip=ip),
100
- Boolean(enable_input_d).ir_value(loc=loc, ip=ip),
101
- loc=loc,
102
- ip=ip,
103
- )
93
+ with cute.arch.elect_one():
94
+ nvvm.tcgen05_mma(
95
+ nvvm.Tcgen05MMAKind.F16,
96
+ NVVM_CTA_GROUP_MAP[cta_group],
97
+ _make_tmem_llvm_ptr(d_tmem, loc=loc, ip=ip),
98
+ Uint64(a_desc).ir_value(loc=loc, ip=ip),
99
+ Uint64(b_desc).ir_value(loc=loc, ip=ip),
100
+ Int32(idesc).ir_value(loc=loc, ip=ip),
101
+ Boolean(enable_input_d).ir_value(loc=loc, ip=ip),
102
+ loc=loc,
103
+ ip=ip,
104
+ )
105
106
107
@dsl_user_op
@@ -115,17 +116,18 @@ def mma_ts_f16(
116
loc=None,
117
ip=None,
118
) -> None:
118
- nvvm.tcgen05_mma(
119
- nvvm.Tcgen05MMAKind.F16,
120
- NVVM_CTA_GROUP_MAP[cta_group],
121
- _make_tmem_llvm_ptr(d_tmem, loc=loc, ip=ip),
122
- _make_tmem_llvm_ptr(a_tmem, loc=loc, ip=ip),
123
- Uint64(b_desc).ir_value(loc=loc, ip=ip),
124
- Int32(idesc).ir_value(loc=loc, ip=ip),
125
- Boolean(enable_input_d).ir_value(loc=loc, ip=ip),
126
- loc=loc,
127
- ip=ip,
128
- )
119
+ with cute.arch.elect_one():
120
+ nvvm.tcgen05_mma(
121
+ nvvm.Tcgen05MMAKind.F16,
122
+ NVVM_CTA_GROUP_MAP[cta_group],
123
+ _make_tmem_llvm_ptr(d_tmem, loc=loc, ip=ip),
124
+ _make_tmem_llvm_ptr(a_tmem, loc=loc, ip=ip),
125
+ Uint64(b_desc).ir_value(loc=loc, ip=ip),
126
+ Int32(idesc).ir_value(loc=loc, ip=ip),
127
+ Boolean(enable_input_d).ir_value(loc=loc, ip=ip),
128
+ loc=loc,
129
+ ip=ip,
130
+ )
131
132
133
@dsl_user_op
@@ -133,15 +135,17 @@ def commit(mbar, cta_mask=None, cta_group: int = 1, *, loc=None, ip=None):
135
mbar_llvm = mbar.to_llvm_ptr(loc=loc, ip=ip)
136
group = NVVM_CTA_GROUP_MAP[cta_group]
137
if cutlass.const_expr(cta_mask is not None):
136
- nvvm.tcgen05_commit_arrive(
137
- mbar_llvm,
138
- multicast_mask=cta_mask.ir_value(loc=loc, ip=ip),
139
- group=group,
140
- loc=loc,
141
- ip=ip,
142
- )
138
+ with cute.arch.elect_one():
139
+ nvvm.tcgen05_commit_arrive(
140
+ mbar_llvm,
141
+ multicast_mask=cta_mask.ir_value(loc=loc, ip=ip),
142
+ group=group,
143
+ loc=loc,
144
+ ip=ip,
145
+ )
146
else:
144
- nvvm.tcgen05_commit_arrive(mbar_llvm, group=group, loc=loc, ip=ip)
147
+ with cute.arch.elect_one():
148
+ nvvm.tcgen05_commit_arrive(mbar_llvm, group=group, loc=loc, ip=ip)
149
150
151
@dsl_user_op
vllm/model_executor/layers/mamba/ops/gdn_chunk_cutedsl/__init__.py
+23
-28
@@ -174,31 +174,31 @@ def chunk_gated_delta_rule_cutedsl(
174
When ``core_attn_out`` is provided, ``output`` is an unsqueezed view of
175
that buffer.
176
"""
177
- q_3d = q.squeeze(0)
178
- k_3d = k.squeeze(0)
179
- v_3d = v.squeeze(0)
180
- g_2d = g.squeeze(0)
181
- beta_2d = beta.squeeze(0)
182
-
183
- _, _, head_k_dim = k_3d.shape
184
- _, num_v_heads, head_v_dim = v_3d.shape
177
+ q = q.squeeze(0)
178
+ k = k.squeeze(0)
179
+ v = v.squeeze(0)
180
+ g = g.squeeze(0)
181
+ beta = beta.squeeze(0)
182
+
183
+ _, _, K_dim = k.shape
184
+ _, num_v_heads, V_dim = v.shape
185
chunk_size = 64
186
upper_bound_chunks = chunk_indices.shape[0]
187
pad_t = upper_bound_chunks * chunk_size
188
total_chunks_ptr = chunk_offsets[-1:]
189
190
- g_cu = torch.empty_like(g_2d, dtype=torch.float32)
191
- u = q_3d.new_empty(pad_t, num_v_heads, head_v_dim)
192
- w = q_3d.new_empty(pad_t, num_v_heads, head_k_dim)
190
+ g_cu = torch.empty_like(g, dtype=torch.float32)
191
+ u = q.new_empty(pad_t, num_v_heads, V_dim)
192
+ w = q.new_empty(pad_t, num_v_heads, K_dim)
193
194
num_sms = torch.cuda.get_device_properties(q.device).multi_processor_count
195
kkt_inv_uw_cutedsl(
196
- k_3d,
197
- v_3d,
196
+ k,
197
+ v,
198
u,
199
w,
200
- g_2d,
201
- beta_2d,
200
+ g,
201
+ beta,
202
g_cu,
203
cu_seqlens,
204
chunk_indices,
@@ -206,16 +206,11 @@ def chunk_gated_delta_rule_cutedsl(
206
num_sms=num_sms,
207
)
208
209
- h = k_3d.new_empty(
210
- upper_bound_chunks,
211
- num_v_heads,
212
- head_v_dim,
213
- head_k_dim,
214
- )
215
- v_new = q_3d.new_empty(pad_t, num_v_heads, head_v_dim)
209
+ h = k.new_empty(upper_bound_chunks, num_v_heads, V_dim, K_dim)
210
+ v_new = q.new_empty(pad_t, num_v_heads, V_dim)
211
final_state = torch.empty_like(initial_state)
212
h_cutedsl(
218
- k_3d,
213
+ k,
214
u,
215
w,
216
v_new,
@@ -227,12 +222,12 @@ def chunk_gated_delta_rule_cutedsl(
222
chunk_offsets,
223
)
224
230
- output = core_attn_out if core_attn_out is not None else torch.empty_like(v_3d)
231
- scale = head_k_dim**-0.5
225
+ output = core_attn_out if core_attn_out is not None else torch.empty_like(v)
226
+ scale = K_dim**-0.5
227
o_cutedsl(
233
- q_3d,
234
- k_3d,
235
- v_new.view(upper_bound_chunks, chunk_size, num_v_heads, head_v_dim),
228
+ q,
229
+ k,
230
+ v_new,
231
h,
232
g_cu,
233
output,
vllm/model_executor/layers/mamba/ops/gdn_chunk_cutedsl/kernel_h.py
+89
-90
@@ -66,13 +66,12 @@ class Sm100ChunkHKernel:
66
stride=(64, 0, (1, self.BT * 64), self.BT * dim),
67
)
68
slayout = cute.make_composed_layout(swizzle_128B, 0, slayout)
69
- atom, tma_tensor = cpasync.make_tiled_tma_atom(
69
+ return cpasync.make_tiled_tma_atom(
70
op,
71
cute.logical_divide(tensor, (None, None, 64)),
72
slayout,
73
cta_tiler=(self.BT, 1, dim),
74
)
75
- return atom, tma_tensor, slayout
75
76
@cute.jit
77
def _make_h_tma_args(self, tensor: cute.Tensor, op: cpasync.TmaCopyOp):
@@ -84,13 +83,12 @@ class Sm100ChunkHKernel:
83
stride=(0, 0, num_elems, (1, self.V_dim * num_elems)),
84
)
85
slayout = cute.make_composed_layout(swizzle_128B, 0, slayout)
87
- atom, tma_tensor = cpasync.make_tiled_tma_atom(
86
+ return cpasync.make_tiled_tma_atom(
87
op,
88
cute.logical_divide(tensor, (None, None, None, num_elems)),
89
slayout,
90
cta_tiler=(1, 1, self.V_dim, self.K_dim),
91
)
93
- return atom, tma_tensor, slayout
92
93
@cute.jit
94
def __call__(
@@ -110,39 +108,39 @@ class Sm100ChunkHKernel:
108
tma_g2s = cpasync.CopyBulkTensorTileG2SOp()
109
tma_s2g = cpasync.CopyBulkTensorTileS2GOp()
110
113
- K_args = self._make_bf16_tma_args(K, self.K_dim, tma_g2s, self.num_stages)
114
- V_args = self._make_bf16_tma_args(V, self.V_dim, tma_g2s, self.num_stages)
115
- W_args = self._make_bf16_tma_args(W, self.K_dim, tma_g2s, self.num_stages)
116
- V_new_args = self._make_bf16_tma_args(V_new, self.V_dim, tma_s2g, 1)
117
- H0_args = self._make_h_tma_args(h0, tma_g2s)
118
- HT_args = self._make_h_tma_args(ht, tma_s2g)
119
- H_args = self._make_h_tma_args(h, tma_s2g)
111
+ K_tma = self._make_bf16_tma_args(K, self.K_dim, tma_g2s, self.num_stages)
112
+ V_tma = self._make_bf16_tma_args(V, self.V_dim, tma_g2s, self.num_stages)
113
+ W_tma = self._make_bf16_tma_args(W, self.K_dim, tma_g2s, self.num_stages)
114
+ V_new_tma = self._make_bf16_tma_args(V_new, self.V_dim, tma_s2g, 1)
115
+ H0_tma = self._make_h_tma_args(h0, tma_g2s)
116
+ HT_tma = self._make_h_tma_args(ht, tma_s2g)
117
+ H_tma = self._make_h_tma_args(h, tma_s2g)
118
119
grid = (self.Hv, h0.shape[0], 1)
120
block = (self.num_warps * 32, 1, 1)
121
self.kernel(
124
- K_args,
125
- V_args,
126
- W_args,
127
- V_new_args,
128
- H0_args,
129
- HT_args,
130
- H_args,
122
+ K_tma,
123
+ V_tma,
124
+ W_tma,
125
+ V_new_tma,
126
+ H0_tma,
127
+ HT_tma,
128
+ H_tma,
129
g_cu,
130
cu_seqlens,
131
chunk_offsets,
134
- ).launch(grid=grid, block=block, stream=stream)
132
+ ).launch(grid=grid, block=block, min_blocks_per_mp=1, stream=stream)
133
134
@cute.kernel
135
def kernel(
136
self,
139
- K_args: tuple[cute.CopyAtom, cute.Tensor, cute.ComposedLayout],
140
- V_args: tuple[cute.CopyAtom, cute.Tensor, cute.ComposedLayout],
141
- W_args: tuple[cute.CopyAtom, cute.Tensor, cute.ComposedLayout],
142
- V_new_args: tuple[cute.CopyAtom, cute.Tensor, cute.ComposedLayout],
143
- H0_args: tuple[cute.CopyAtom, cute.Tensor, cute.ComposedLayout],
144
- HT_args: tuple[cute.CopyAtom, cute.Tensor, cute.ComposedLayout],
145
- H_args: tuple[cute.CopyAtom, cute.Tensor, cute.ComposedLayout],
137
+ K_tma: cpasync.TmaInfo,
138
+ V_tma: cpasync.TmaInfo,
139
+ W_tma: cpasync.TmaInfo,
140
+ V_new_tma: cpasync.TmaInfo,
141
+ H0_tma: cpasync.TmaInfo,
142
+ HT_tma: cpasync.TmaInfo,
143
+ H_tma: cpasync.TmaInfo,
144
g_cu: cute.Tensor,
145
cu_seqlens: cute.Tensor,
146
chunk_offsets: cute.Tensor,
@@ -158,14 +156,6 @@ class Sm100ChunkHKernel:
156
num_stages = self.num_stages
157
is_f32 = self.h_dtype == Float32
158
161
- K_tma_atom, tmaK, sK_layout = K_args
162
- V_tma_atom, tmaV, sV_layout = V_args
163
- W_tma_atom, tmaW, sW_layout = W_args
164
- V_new_tma_atom, tmaV_new, sV_new_layout = V_new_args
165
- H0_tma_atom, tmaH0, sH0_layout = H0_args
166
- HT_tma_atom, tmaHT, _ = HT_args
167
- H_tma_atom, tmaH, sH_layout = H_args
168
-
159
def allocate_tensor(smem, dtype, layout):
160
return smem.allocate_tensor(
161
dtype, layout.outer, byte_alignment=128, swizzle=layout.inner
@@ -174,12 +164,14 @@ class Sm100ChunkHKernel:
164
smem = cutlass.utils.SmemAllocator()
165
166
# remove size=1 modes
177
- sW = allocate_tensor(smem, BFloat16, sW_layout)[None, 0, None, None]
178
- sV = allocate_tensor(smem, BFloat16, sV_layout)[None, 0, None, None]
179
- sK = allocate_tensor(smem, BFloat16, sK_layout)[None, 0, None, None]
180
- sH0 = allocate_tensor(smem, self.h_dtype, sH0_layout)[0, 0, None, None]
181
- sH = allocate_tensor(smem, BFloat16, sH_layout)[0, 0, None, None]
182
- sV_new = allocate_tensor(smem, BFloat16, sV_new_layout)[None, 0, None, 0]
167
+ sW = allocate_tensor(smem, BFloat16, W_tma.smem_layout)[None, 0, None, None]
168
+ sV = allocate_tensor(smem, BFloat16, V_tma.smem_layout)[None, 0, None, None]
169
+ sK = allocate_tensor(smem, BFloat16, K_tma.smem_layout)[None, 0, None, None]
170
+ sH0 = allocate_tensor(smem, self.h_dtype, H0_tma.smem_layout)[0, 0, None, None]
171
+ sH = allocate_tensor(smem, BFloat16, H_tma.smem_layout)[0, 0, None, None]
172
+ sV_new = allocate_tensor(smem, BFloat16, V_new_tma.smem_layout)[
173
+ None, 0, None, 0
174
+ ]
175
176
s_v_scale = smem.allocate_array(Float32, BT)
177
tma_mbar = smem.allocate_array(Int64, num_stages)
@@ -206,13 +198,13 @@ class Sm100ChunkHKernel:
198
cute.arch.mbarrier_init(h0_mbar, 1)
199
cute.arch.mbarrier_init_fence()
200
elif warp_id == 1:
209
- cpasync.prefetch_descriptor(H0_tma_atom)
210
- cpasync.prefetch_descriptor(W_tma_atom)
211
- cpasync.prefetch_descriptor(V_tma_atom)
212
- cpasync.prefetch_descriptor(K_tma_atom)
213
- cpasync.prefetch_descriptor(HT_tma_atom)
214
- cpasync.prefetch_descriptor(H_tma_atom)
215
- cpasync.prefetch_descriptor(V_new_tma_atom)
201
+ cpasync.prefetch_descriptor(H0_tma.atom)
202
+ cpasync.prefetch_descriptor(W_tma.atom)
203
+ cpasync.prefetch_descriptor(V_tma.atom)
204
+ cpasync.prefetch_descriptor(K_tma.atom)
205
+ cpasync.prefetch_descriptor(HT_tma.atom)
206
+ cpasync.prefetch_descriptor(H_tma.atom)
207
+ cpasync.prefetch_descriptor(V_new_tma.atom)
208
cute.arch.sync_threads()
209
210
bos = cu_seqlens[seq_id]
@@ -233,14 +225,21 @@ class Sm100ChunkHKernel:
225
H0_size = V_dim * K_dim * self.h_dtype.width // 8
226
cute.arch.mbarrier_arrive_and_expect_tx(h0_mbar, H0_size)
227
simple_tma_copy(
236
- H0_tma_atom, tmaH0[seq_id, head_id, None, None], sH0, h0_mbar
228
+ H0_tma.atom,
229
+ H0_tma.tma_tensor[seq_id, head_id, None, None],
230
+ sH0,
231
+ h0_mbar,
232
)
233
234
# shape: ((BT, num_BT_tiles), (64, 2))
240
- gW_tiles = cute.logical_divide(tmaW[None, head_id, None], (BT, None))
241
- gV_tiles = cute.logical_divide(tmaV[None, head_id, None], (BT, None))
235
+ gW_tiles = cute.logical_divide(
236
+ W_tma.tma_tensor[None, head_id, None], (BT, None)
237
+ )
238
+ gV_tiles = cute.logical_divide(
239
+ V_tma.tma_tensor[None, head_id, None], (BT, None)
240
+ )
241
gK_tiles = cute.logical_divide(
243
- cute.domain_offset((bos, 0), tmaK[None, k_head_id, None]),
242
+ cute.domain_offset((bos, 0), K_tma.tma_tensor[None, k_head_id, None]),
243
(BT, None),
244
)
245
@@ -258,12 +257,12 @@ class Sm100ChunkHKernel:
257
STAGE_SIZE = BT * (K_dim + V_dim + K_dim) * 2
258
cute.arch.mbarrier_arrive_and_expect_tx(mbar, STAGE_SIZE)
259
simple_tma_copy(
261
- W_tma_atom, gW, sW[None, None, stage_id], mbar, EVICT_FIRST
260
+ W_tma.atom, gW, sW[None, None, stage_id], mbar, EVICT_FIRST
261
)
262
simple_tma_copy(
264
- V_tma_atom, gV, sV[None, None, stage_id], mbar, EVICT_FIRST
263
+ V_tma.atom, gV, sV[None, None, stage_id], mbar, EVICT_FIRST
264
)
266
- simple_tma_copy(K_tma_atom, gK, sK[None, None, stage_id], mbar)
265
+ simple_tma_copy(K_tma.atom, gK, sK[None, None, stage_id], mbar)
266
267
stage_id = (stage_id + 1) % num_stages
268
if stage_id == 0:
@@ -295,13 +294,12 @@ class Sm100ChunkHKernel:
294
cute.arch.mbarrier_wait(wh_in_mbar + stage_id, parity)
295
_tcgen05.fence_after_thread_sync()
296
298
- with cute.arch.elect_one():
299
- for i in cutlass.range_constexpr(K_dim // 64):
300
- for j in cutlass.range_constexpr(64 // 16):
301
- hdesc0 = hdesc0_base | ((i * V_dim * 128 + j * 32) >> 4)
302
- wdesc0 = wdesc0_base | ((i * BT * 128 + j * 32) >> 4)
303
- _tcgen05.mma_f16(wh_tmem, hdesc0, wdesc0, wh_idesc, True)
304
- _tcgen05.commit(wh_done_mbar + stage_id)
297
+ for i in cutlass.range_constexpr(K_dim // 64):
298
+ for j in cutlass.range_constexpr(64 // 16):
299
+ hdesc0 = hdesc0_base | ((i * V_dim * 128 + j * 32) >> 4)
300
+ wdesc0 = wdesc0_base | ((i * BT * 128 + j * 32) >> 4)
301
+ _tcgen05.mma_f16(wh_tmem, hdesc0, wdesc0, wh_idesc, True)
302
+ _tcgen05.commit(wh_done_mbar + stage_id)
303
304
##### 2nd MMA: H_new = H + V_new.T @ K #####
305
Kaddr0 = sK[None, None, stage_id].iterator.toint()
@@ -310,12 +308,11 @@ class Sm100ChunkHKernel:
308
cute.arch.mbarrier_wait(vk_in_mbar + stage_id, parity)
309
_tcgen05.fence_after_thread_sync()
310
313
- with cute.arch.elect_one():
314
- for k in cutlass.range_constexpr(BT // 16):
315
- vtmem0 = v_tmem_base + k * 8
316
- kdesc0 = kdesc0_base | ((k * 16 * 128) >> 4)
317
- _tcgen05.mma_ts_f16(vk_tmem, vtmem0, kdesc0, vk_idesc, True)
318
- _tcgen05.commit(vk_done_mbar + stage_id)
311
+ for k in cutlass.range_constexpr(BT // 16):
312
+ vtmem0 = v_tmem_base + k * 8
313
+ kdesc0 = kdesc0_base | ((k * 16 * 128) >> 4)
314
+ _tcgen05.mma_ts_f16(vk_tmem, vtmem0, kdesc0, vk_idesc, True)
315
+ _tcgen05.commit(vk_done_mbar + stage_id)
316
317
stage_id = (stage_id + 1) % num_stages
318
if stage_id == 0:
@@ -331,13 +328,12 @@ class Sm100ChunkHKernel:
328
cute.arch.mbarrier_wait(wh_in_mbar + stage_id, parity)
329
_tcgen05.fence_after_thread_sync()
330
334
- with cute.arch.elect_one():
335
- for i in cutlass.range_constexpr(K_dim // 64):
336
- for j in cutlass.range_constexpr(64 // 16):
337
- htmem = h_tmem_base + i * 32 + j * 8
338
- wdesc = wdesc_base | ((i * BT * 128 + j * 32) >> 4)
339
- _tcgen05.mma_ts_f16(wh_tmem, htmem, wdesc, wh_idesc, True)
340
- _tcgen05.commit(wh_done_mbar + stage_id)
331
+ for i in cutlass.range_constexpr(K_dim // 64):
332
+ for j in cutlass.range_constexpr(64 // 16):
333
+ htmem = h_tmem_base + i * 32 + j * 8
334
+ wdesc = wdesc_base | ((i * BT * 128 + j * 32) >> 4)
335
+ _tcgen05.mma_ts_f16(wh_tmem, htmem, wdesc, wh_idesc, True)
336
+ _tcgen05.commit(wh_done_mbar + stage_id)
337
338
##### 2nd MMA: H_new = H + V_new.T @ K #####
339
Kaddr = sK[None, None, stage_id].iterator.toint()
@@ -346,12 +342,11 @@ class Sm100ChunkHKernel:
342
cute.arch.mbarrier_wait(vk_in_mbar + stage_id, parity)
343
_tcgen05.fence_after_thread_sync()
344
349
- with cute.arch.elect_one():
350
- for k in cutlass.range_constexpr(BT // 16):
351
- vtmem = v_tmem_base + k * 8
352
- kdesc = kdesc_base | ((k * 16 * 128) >> 4)
353
- _tcgen05.mma_ts_f16(vk_tmem, vtmem, kdesc, vk_idesc, True)
354
- _tcgen05.commit(vk_done_mbar + stage_id)
345
+ for k in cutlass.range_constexpr(BT // 16):
346
+ vtmem = v_tmem_base + k * 8
347
+ kdesc = kdesc_base | ((k * 16 * 128) >> 4)
348
+ _tcgen05.mma_ts_f16(vk_tmem, vtmem, kdesc, vk_idesc, True)
349
+ _tcgen05.commit(vk_done_mbar + stage_id)
350
351
stage_id = (stage_id + 1) % num_stages
352
if stage_id == 0:
@@ -421,7 +416,7 @@ class Sm100ChunkHKernel:
416
).load()
417
)
418
424
- for j in cutlass.range_constexpr(32):
419
+ for j in cutlass.range(32, vectorize=True):
420
h_f32[j] *= h_scale
421
_tcgen05.st(warp_id_ * 32, vk_tmem + i * 32, "32x32b", 32, h_f32)
422
@@ -435,8 +430,10 @@ class Sm100ChunkHKernel:
430
fence_before_tma_store()
431
if warp_id_ == 3:
432
h_src = sH if cutlass.const_expr(is_f32) else sH0
438
- h_dst = tmaH[chunk_offset + chunk_id, head_id, None, None]
439
- simple_tma_copy(H_tma_atom, h_src, h_dst)
433
+ h_dst = H_tma.tma_tensor[
434
+ chunk_offset + chunk_id, head_id, None, None
435
+ ]
436
+ simple_tma_copy(H_tma.atom, h_src, h_dst)
437
with cute.arch.elect_one():
438
cute.arch.cp_async_bulk_commit_group()
439
@@ -490,7 +487,7 @@ class Sm100ChunkHKernel:
487
h_f32.store(
488
_tcgen05.ld(warp_id_ * 32, vk_tmem + i * 32, "32x32b", 32)
489
)
493
- for j in cutlass.range_constexpr(32):
490
+ for j in cutlass.range(32, vectorize=True):
491
h_f32[j] *= h_scale
492
_tcgen05.st(warp_id_ * 32, vk_tmem + i * 32, "32x32b", 32, h_f32)
493
_tcgen05.wait_st()
@@ -501,8 +498,10 @@ class Sm100ChunkHKernel:
498
cute.arch.barrier(barrier_id=1, number_of_threads=128)
499
fence_before_tma_store()
500
if warp_id_ == 3:
504
- h_dst = tmaH[chunk_offset + chunk_id, head_id, None, None]
505
- simple_tma_copy(H_tma_atom, sH, h_dst)
501
+ h_dst = H_tma.tma_tensor[
502
+ chunk_offset + chunk_id, head_id, None, None
503
+ ]
504
+ simple_tma_copy(H_tma.atom, sH, h_dst)
505
with cute.arch.elect_one():
506
cute.arch.cp_async_bulk_commit_group()
507
@@ -530,8 +529,8 @@ class Sm100ChunkHKernel:
529
cute.arch.barrier(barrier_id=1, number_of_threads=128)
530
531
if warp_id_ == 0:
533
- ht_dst = tmaHT[seq_id, head_id, None, None]
534
- simple_tma_copy(HT_tma_atom, sH0, ht_dst)
532
+ ht_dst = HT_tma.tma_tensor[seq_id, head_id, None, None]
533
+ simple_tma_copy(HT_tma.atom, sH0, ht_dst)
534
with cute.arch.elect_one():
535
cute.arch.cp_async_bulk_commit_group()
536
if warp_id_ == 1:
@@ -551,7 +550,7 @@ class Sm100ChunkHKernel:
550
551
# ((BT, num_BT_tiles), V_dim)
552
gV_new_tiles = cute.logical_divide(
554
- tmaV_new[None, head_id, None], (BT, None)
553
+ V_new_tma.tma_tensor[None, head_id, None], (BT, None)
554
)
555
556
# sV shape: [BT, (64, V_dim/64), num_stages]
@@ -653,7 +652,7 @@ class Sm100ChunkHKernel:
652
fence_before_tma_store()
653
if warp_id == 3:
654
gV = gV_new_tiles[(None, chunk_offset + chunk_id), None]
656
- simple_tma_copy(V_new_tma_atom, sV_new, gV)
655
+ simple_tma_copy(V_new_tma.atom, sV_new, gV)
656
with cute.arch.elect_one():
657
cute.arch.cp_async_bulk_commit_group()
658
vllm/model_executor/layers/mamba/ops/gdn_chunk_cutedsl/kernel_kkt_inv_uw.py
+297
-231
@@ -11,6 +11,8 @@ from quack.compile_utils import make_fake_tensor
11
12
from vllm.cute_utils import (
13
EVICT_FIRST,
14
+ _bf16x2_neg,
15
+ _bf16x2_sub,
16
_tcgen05,
17
cvt,
18
fence_before_tma_store,
@@ -47,7 +49,7 @@ class Sm100ChunkUWKernel:
49
50
# hard-code
51
self.BT = 64
50
- self.num_warps = 2 + 4 + 4
52
+ self.num_warps = 4 + 4 + 4
53
54
@cute.jit
55
def _make_tma_args(
@@ -68,13 +70,12 @@ class Sm100ChunkUWKernel:
70
71
# we need to convert gmem layout to (T, H, (64, D/64)) for make_tiled_tma_atom()
72
# to emit a single 4D TMA. otherwise, it will emit (D/64)x 3D TMA.
71
- atom, tma_tensor = cpasync.make_tiled_tma_atom(
73
+ return cpasync.make_tiled_tma_atom(
74
op,
75
cute.logical_divide(tensor, (None, None, 64)),
76
slayout,
77
cta_tiler=(self.BT, 1, dim),
78
)
77
- return atom, tma_tensor, slayout
79
80
@cute.jit
81
def __call__(
@@ -95,33 +96,33 @@ class Sm100ChunkUWKernel:
96
tma_g2s = cpasync.CopyBulkTensorTileG2SOp()
97
tma_s2g = cpasync.CopyBulkTensorTileS2GOp()
98
98
- K_args = self._make_tma_args(K, self.K_dim, self.num_stages, tma_g2s)
99
- V_args = self._make_tma_args(V, self.V_dim, self.num_stages, tma_g2s)
100
- U_args = self._make_tma_args(U, self.V_dim, 1, tma_s2g)
101
- W_args = self._make_tma_args(W, self.K_dim, 1, tma_s2g)
99
+ K_tma = self._make_tma_args(K, self.K_dim, self.num_stages, tma_g2s)
100
+ V_tma = self._make_tma_args(V, self.V_dim, self.num_stages, tma_g2s)
101
+ U_tma = self._make_tma_args(U, self.V_dim, 1, tma_s2g)
102
+ W_tma = self._make_tma_args(W, self.K_dim, 1, tma_s2g)
103
104
grid = (num_sms // self.Hv, self.Hv, 1)
105
block = (self.num_warps * 32, 1, 1)
106
self.kernel(
106
- K_args,
107
- V_args,
108
- U_args,
109
- W_args,
107
+ K_tma,
108
+ V_tma,
109
+ U_tma,
110
+ W_tma,
111
g,
112
beta,
113
g_cu,
114
cu_seqlens,
115
chunk_indices,
116
total_chunks,
116
- ).launch(grid=grid, block=block, stream=stream)
117
+ ).launch(grid=grid, block=block, min_blocks_per_mp=1, stream=stream)
118
119
@cute.kernel
120
def kernel(
121
self,
121
- K_args: tuple[cute.CopyAtom, cute.Tensor, cute.ComposedLayout],
122
- V_args: tuple[cute.CopyAtom, cute.Tensor, cute.ComposedLayout],
123
- U_args: tuple[cute.CopyAtom, cute.Tensor, cute.ComposedLayout],
124
- W_args: tuple[cute.CopyAtom, cute.Tensor, cute.ComposedLayout],
122
+ K_tma: cpasync.TmaInfo,
123
+ V_tma: cpasync.TmaInfo,
124
+ U_tma: cpasync.TmaInfo,
125
+ W_tma: cpasync.TmaInfo,
126
g: cute.Tensor,
127
beta: cute.Tensor,
128
g_cu: cute.Tensor,
@@ -142,10 +143,10 @@ class Sm100ChunkUWKernel:
143
V_dim = self.V_dim
144
num_stages = self.num_stages
145
145
- K_tma_atom, tmaK, sK_layout = K_args
146
- V_tma_atom, tmaV, sV_layout = V_args
147
- U_tma_atom, tmaU, sU_layout = U_args
148
- W_tma_atom, tmaW, sW_layout = W_args
146
+ INV_BAR = 1
147
+ EPI_BAR = 2
148
+ SCAN_BAR = 3
149
+ TMEM_ALLOC_BAR = 4
150
151
def allocate_tensor(smem, dtype, layout):
152
return smem.allocate_tensor(
@@ -153,22 +154,20 @@ class Sm100ChunkUWKernel:
154
)
155
156
smem = cutlass.utils.SmemAllocator()
156
- sK = allocate_tensor(smem, BFloat16, sK_layout)[None, 0, None, None]
157
- sV = allocate_tensor(smem, BFloat16, sV_layout)[None, 0, None, None]
158
- sU = allocate_tensor(smem, BFloat16, sU_layout)[None, 0, None, 0]
159
- sW = allocate_tensor(smem, BFloat16, sW_layout)[None, 0, None, 0]
157
+ sK = allocate_tensor(smem, BFloat16, K_tma.smem_layout)[None, 0, None, None]
158
+ sV = allocate_tensor(smem, BFloat16, V_tma.smem_layout)[None, 0, None, None]
159
+ sU = allocate_tensor(smem, BFloat16, U_tma.smem_layout)[None, 0, None, 0]
160
+ sW = allocate_tensor(smem, BFloat16, W_tma.smem_layout)[None, 0, None, 0]
161
161
- swizzle_128B = cute.make_swizzle(3, 4, 3)
162
- sA_layout = cute.make_layout((BT, (64, 1)), stride=(64, (1, BT * 64)))
163
- sA_layout = cute.make_composed_layout(swizzle_128B, 0, sA_layout)
164
- sA = allocate_tensor(smem, BFloat16, sA_layout)
165
- sAi = allocate_tensor(smem, BFloat16, sA_layout)
162
+ sA_ptr = smem.allocate_array(BFloat16, BT * BT, byte_alignment=16)
163
+ sAi_ptr = smem.allocate_array(BFloat16, BT * BT, byte_alignment=16)
164
167
- s_beta = smem.allocate_array(Float32, BT)
168
- s_g_cu_exp = smem.allocate_array(Float32, BT)
169
- s_g_cu = smem.allocate_array(Float32, BT)
165
+ s_beta = smem.allocate_tensor(Float32, cute.make_layout((BT, num_stages)))
166
+ s_g_cu = smem.allocate_tensor(Float32, cute.make_layout((BT, num_stages)))
167
+ s_beta_g = smem.allocate_tensor(Float32, cute.make_layout((BT, num_stages)))
168
169
tma_mbar = smem.allocate_array(Int64, num_stages)
170
+ prep_mbar = smem.allocate_array(Int64, num_stages)
171
mma_kkt_mbar = smem.allocate_array(Int64, num_stages)
172
inv_mbar = smem.allocate_array(Int64, num_stages)
173
mma_u_mbar = smem.allocate_array(Int64, num_stages)
@@ -179,7 +178,7 @@ class Sm100ChunkUWKernel:
178
kkt_tmem = 0
179
U_tmem_base = kkt_tmem + BT
180
Ab_tmem_base = U_tmem_base + V_dim * num_stages
182
- assert Ab_tmem_base + (BT // 2) * num_stages <= 512
181
+ assert Ab_tmem_base + (BT // 2) <= 512
182
183
# prepare ldmatrix/stmatrix ops
184
ldsm_op = warp.LdMatrix8x8x16bOp(num_matrices=4)
@@ -193,6 +192,7 @@ class Sm100ChunkUWKernel:
192
with cute.arch.elect_one():
193
for i in cutlass.range_constexpr(num_stages):
194
cute.arch.mbarrier_init(tma_mbar + i, 1)
195
+ cute.arch.mbarrier_init(prep_mbar + i, 64)
196
cute.arch.mbarrier_init(mma_kkt_mbar + i, 1)
197
cute.arch.mbarrier_init(inv_mbar + i, 128)
198
cute.arch.mbarrier_init(mma_u_mbar + i, 1)
@@ -200,14 +200,14 @@ class Sm100ChunkUWKernel:
200
cute.arch.mbarrier_init(epi_mbar + i, 128)
201
cute.arch.mbarrier_init_fence()
202
elif warp_id == 1:
203
- cpasync.prefetch_descriptor(K_tma_atom)
204
- cpasync.prefetch_descriptor(V_tma_atom)
205
- cpasync.prefetch_descriptor(U_tma_atom)
206
- cpasync.prefetch_descriptor(W_tma_atom)
203
+ cpasync.prefetch_descriptor(K_tma.atom)
204
+ cpasync.prefetch_descriptor(V_tma.atom)
205
+ cpasync.prefetch_descriptor(U_tma.atom)
206
+ cpasync.prefetch_descriptor(W_tma.atom)
207
cute.arch.sync_threads()
208
209
num_global_chunks = total_chunks[0]
210
- if warp_id == 9:
210
+ if warp_id == 11:
211
# TMA warp
212
stage_id = 0
213
parity = 1
@@ -221,12 +221,14 @@ class Sm100ChunkUWKernel:
221
# domain_offset() to shift the pointer first.
222
mbar = tma_mbar + stage_id
223
gK = cute.local_tile(
224
- cute.domain_offset((bos, 0), tmaK[None, k_head_id, None]),
224
+ cute.domain_offset(
225
+ (bos, 0), K_tma.tma_tensor[None, k_head_id, None]
226
+ ),
227
tiler=(BT, K_dim),
228
coord=(chunk_id, 0),
229
)
230
gV = cute.local_tile(
229
- cute.domain_offset((bos, 0), tmaV[None, head_id, None]),
231
+ cute.domain_offset((bos, 0), V_tma.tma_tensor[None, head_id, None]),
232
tiler=(BT, V_dim),
233
coord=(chunk_id, 0),
234
)
@@ -237,18 +239,19 @@ class Sm100ChunkUWKernel:
239
with cute.arch.elect_one():
240
STAGE_SIZE = BT * (K_dim + V_dim) * 2
241
cute.arch.mbarrier_arrive_and_expect_tx(mbar, STAGE_SIZE)
240
- simple_tma_copy(K_tma_atom, gK, sK[None, None, stage_id], mbar)
242
+ simple_tma_copy(K_tma.atom, gK, sK[None, None, stage_id], mbar)
243
simple_tma_copy(
242
- V_tma_atom, gV, sV[None, None, stage_id], mbar, EVICT_FIRST
244
+ V_tma.atom, gV, sV[None, None, stage_id], mbar, EVICT_FIRST
245
)
246
247
stage_id = (stage_id + 1) % num_stages
248
if stage_id == 0:
249
parity ^= 1
250
249
- elif warp_id == 8:
251
+ elif warp_id == 10:
252
# MMA warp
253
_tcgen05.alloc(taddr)
254
+ cute.arch.barrier(barrier_id=TMEM_ALLOC_BAR, number_of_threads=160)
255
256
stage_id = 0
257
parity = 0
@@ -263,8 +266,8 @@ class Sm100ChunkUWKernel:
266
for global_chunk_id in range(bid, num_global_chunks, grid_x):
267
U_tmem = U_tmem_base + V_dim * stage_id
268
W_tmem = U_tmem | (16 << 16)
266
- Ab_tmem = Ab_tmem_base + (BT // 2) * stage_id
267
- Abg_tmem = Ab_tmem | (16 << 16)
269
+ Ab_tmem = Ab_tmem_base
270
+ Abg_tmem = Ab_tmem_base | (16 << 16)
271
272
##### KKT MMA: KKT = K @ K.T #####
273
kaddr = sK[None, None, stage_id].iterator.toint()
@@ -276,18 +279,12 @@ class Sm100ChunkUWKernel:
279
cute.arch.mbarrier_wait(tma_mbar + stage_id, parity)
280
_tcgen05.fence_after_thread_sync()
281
279
- with cute.arch.elect_one():
280
- for i in cutlass.range_constexpr(K_dim // 64):
281
- for j in cutlass.range_constexpr(64 // 16):
282
- kdesc = kdesc_base | ((i * BT * 128 + j * 32) >> 4)
283
- _tcgen05.mma_f16(
284
- kkt_tmem,
285
- kdesc,
286
- kdesc,
287
- kkt_idesc,
288
- (i > 0) or (j > 0),
289
- )
290
- _tcgen05.commit(mma_kkt_mbar + stage_id)
282
+ for i in cutlass.range_constexpr(K_dim // 64):
283
+ for j in cutlass.range_constexpr(64 // 16):
284
+ kdesc = kdesc_base | ((i * BT * 128 + j * 32) >> 4)
285
+ enable_d = (i > 0) or (j > 0)
286
+ _tcgen05.mma_f16(kkt_tmem, kdesc, kdesc, kkt_idesc, enable_d)
287
+ _tcgen05.commit(mma_kkt_mbar + stage_id)
288
289
##### U/W MMA: U = Ab @ V, W = Abg @ K #####
290
vaddr = sV[None, None, stage_id].iterator.toint()
@@ -299,20 +296,15 @@ class Sm100ChunkUWKernel:
296
cute.arch.mbarrier_wait(inv_mbar + stage_id, parity)
297
_tcgen05.fence_after_thread_sync()
298
302
- with cute.arch.elect_one():
303
- for i in cutlass.range_constexpr(BT // 16):
304
- _tcgen05.mma_ts_f16(
305
- W_tmem, Abg_tmem + i * 8, kdesc, w_idesc, i > 0
306
- )
307
- kdesc += (16 * 128) >> 4
308
- _tcgen05.commit(mma_w_mbar + stage_id)
299
+ for i in cutlass.range_constexpr(BT // 16):
300
+ _tcgen05.mma_ts_f16(W_tmem, Abg_tmem + i * 8, kdesc, w_idesc, i > 0)
301
+ kdesc += (16 * 128) >> 4
302
+ _tcgen05.commit(mma_w_mbar + stage_id)
303
310
- for i in cutlass.range_constexpr(BT // 16):
311
- _tcgen05.mma_ts_f16(
312
- U_tmem, Ab_tmem + i * 8, vdesc, u_idesc, i > 0
313
- )
314
- vdesc += (16 * 128) >> 4
315
- _tcgen05.commit(mma_u_mbar + stage_id)
304
+ for i in cutlass.range_constexpr(BT // 16):
305
+ _tcgen05.mma_ts_f16(U_tmem, Ab_tmem + i * 8, vdesc, u_idesc, i > 0)
306
+ vdesc += (16 * 128) >> 4
307
+ _tcgen05.commit(mma_u_mbar + stage_id)
308
309
stage_id = (stage_id + 1) % num_stages
310
if stage_id == 0:
@@ -321,24 +313,124 @@ class Sm100ChunkUWKernel:
313
cute.arch.mbarrier_wait(epi_mbar + stage_id, parity ^ 1)
314
_tcgen05.dealloc()
315
316
+ elif warp_id >= 8:
317
+ # dedicated prep warps for beta and gate, consumed by INV warps
318
+ stage_id = 0
319
+ parity = 0
320
+ tid_ = tid % 128
321
+ warp_id_ = warp_id % 4
322
+
323
+ for global_chunk_id in range(bid, num_global_chunks, grid_x):
324
+ seq_id = chunk_indices[global_chunk_id, 0]
325
+ chunk_id = chunk_indices[global_chunk_id, 1]
326
+ bos = cu_seqlens[seq_id]
327
+ eos = cu_seqlens[seq_id + 1]
328
+ off_t = bos + chunk_id * BT
329
+ t = off_t + tid_
330
+
331
+ in_bounds = t < eos
332
+ beta_val = beta[t, head_id] if in_bounds else Float32(0.0)
333
+ g_val = g[t, head_id] if in_bounds else Float32(0.0)
334
+
335
+ # warp-local prefix scan
336
+ for i in cutlass.range_constexpr(5):
337
+ offset = cutlass.const_expr(1 << i)
338
+ lower = cute.arch.shuffle_sync_up(g_val, offset, mask_and_clamp=0)
339
+ if lane_id >= offset:
340
+ g_val += lower
341
+
342
+ # Delay the stage-reuse wait until just before touching smem:
343
+ # global loads and the warp-local scan do not use staged buffers.
344
+ if warp_id_ == 0:
345
+ cute.arch.mbarrier_wait(inv_mbar + stage_id, parity ^ 1)
346
+ cute.arch.barrier(barrier_id=SCAN_BAR, number_of_threads=BT)
347
+
348
+ # Store beta and the per-warp scan totals for the cross-warp fixup.
349
+ s_beta[tid_, stage_id] = beta_val
350
+ if lane_id == 31:
351
+ s_g_cu[warp_id_, stage_id] = g_val
352
+ cute.arch.barrier(barrier_id=SCAN_BAR, number_of_threads=BT)
353
+
354
+ # Add the sum from the lower prep warp.
355
+ if warp_id_ == 1:
356
+ g_val += s_g_cu[0, stage_id]
357
+ cute.arch.barrier(barrier_id=SCAN_BAR, number_of_threads=BT)
358
+
359
+ if in_bounds:
360
+ g_cu[t, head_id] = g_val
361
+
362
+ s_g_cu[tid_, stage_id] = g_val
363
+ s_beta_g[tid_, stage_id] = beta_val * cute.math.exp(g_val)
364
+ cute.arch.mbarrier_arrive(prep_mbar + stage_id)
365
+
366
+ stage_id = (stage_id + 1) % num_stages
367
+ if stage_id == 0:
368
+ parity ^= 1
369
+
370
elif warp_id >= 4:
371
# inv warps
372
tid_ = tid % 128
373
warp_id_ = warp_id % 4
374
375
+ def store_ab_abg(
376
+ Ai_f32, s_beta, s_beta_g, warp_id_, lane_id, tile_col, Ab_tmem_base
377
+ ):
378
+ # compute Ab and Abg from Ai, then store to tmem
379
+ beta_col = cute.make_rmem_tensor((2, 2), Float32)
380
+ beta_g_col = cute.make_rmem_tensor((2, 2), Float32)
381
+
382
+ for i in cutlass.range_constexpr(2):
383
+ base = tile_col * 16 + i * 8 + (lane_id % 4) * 2
384
+ for j in cutlass.range_constexpr(2):
385
+ beta_col[j, i] = s_beta[base + j]
386
+ beta_g_col[j, i] = s_beta_g[base + j]
387
+
388
+ # without conversion to TensorSSA, cutlass.range(vectorize=True) fails
389
+ beta_col = beta_col.load()
390
+ beta_g_col = beta_g_col.load()
391
+
392
+ Ab_f32 = cute.make_rmem_tensor(8, Float32)
393
+ Abg_f32 = cute.make_rmem_tensor(8, Float32)
394
+ for i in cutlass.range(8, vectorize=True):
395
+ scale_idx = (i // 4) * 2 + (i % 2)
396
+ Ab_f32[i] = Ai_f32[i] * beta_col[scale_idx]
397
+ Abg_f32[i] = Ai_f32[i] * beta_g_col[scale_idx]
398
+
399
+ Ab = Ab_f32.load().to(BFloat16)
400
+ Abg = Abg_f32.load().to(BFloat16)
401
+ Ab_tmem = Ab_tmem_base + tile_col * 8
402
+ _tcgen05.st(warp_id_ * 32, Ab_tmem, "16x128b", 2, Ab)
403
+ _tcgen05.st(warp_id_ * 32 + 16, Ab_tmem, "16x128b", 2, Abg)
404
+
405
+ # clear the Ab/Abg tmem buffer once before mainloop
406
+ # this is to keep the upper triangular tiles zeros
407
+ cute.arch.barrier(barrier_id=TMEM_ALLOC_BAR, number_of_threads=160)
408
+ zeros_ = cute.make_rmem_tensor(BT // 2, Float32)
409
+ zeros_.fill(0.0)
410
+ _tcgen05.st(warp_id_ * 32, Ab_tmem_base, "32x32b", BT // 2, zeros_)
411
+
412
stage_id = 0
413
parity = 0
414
332
- # view into (16,16) sub-tiles, then ldmatrix layout
333
- sA_ldsm = cute.logical_divide(sA, (16, cute.make_layout((8, 2))))
334
- sAi_ldsm = cute.logical_divide(sAi, (16, cute.make_layout((8, 2))))
335
- sA_ldsm = sA_ldsm[(lane_id % 16, None), ((None, lane_id // 16), None)]
336
- sAi_ldsm = sAi_ldsm[(lane_id % 16, None), ((None, lane_id // 16), None)]
415
+ # for sA, we can avoid bank conflict without using swizzling because
416
+ # this is only used as tmp buffer between rmem<->smem, no gmem interactions.
417
+ # to do so, we can put (8,8) tile contiguous in memory. logically, we are
418
+ # partitioning (64,64) tile into 4x (16,16) tiles. to make indexing easier
419
+ # later, we view (16,16) tile as (32,8) tile here.
420
+ # (4,4) is (row_tile, col_tile).
421
+ sA_layout = cute.make_layout(((8, 32), (4, 4)))
422
+ sA = cute.make_tensor(sA_ptr, sA_layout)
423
+ sAi = cute.make_tensor(sAi_ptr, sA_layout)
424
+
425
+ # pre-compute ldmatrix addresses
426
+ sA_ldsm = sA[(None, lane_id), None]
427
+ sAi_ldsm = sAi[(None, lane_id), None]
428
429
# init Ai smem buffer with zeros (only the first 48 rows)
339
- for i in cutlass.range_constexpr((BT // 4 * 3) * BT // 128):
340
- idx = i * 128 + tid_
341
- sAi[idx // BT, idx % BT] = BFloat16(0.0)
430
+ zeros_bf16 = cute.make_rmem_tensor(8, BFloat16)
431
+ zeros_bf16.fill(0.0)
432
+ for i in cutlass.range_constexpr(3):
433
+ cute.copy(stsm_atom, zeros_bf16, sAi_ldsm[None, (i, warp_id_)])
434
435
# indices for ldmatrix layout later
436
row_indices = cute.make_rmem_tensor((1, 2, 1), Int32)
@@ -360,61 +452,31 @@ class Sm100ChunkUWKernel:
452
eos = cu_seqlens[seq_id + 1]
453
off_t = bos + chunk_id * BT
454
363
- t = off_t + tid_
364
-
365
- ##### Phase 1: load g and beta #####
366
- if tid_ < BT:
367
- in_bounds = t < eos
368
- beta_val = beta[t, head_id] if in_bounds else Float32(0.0)
369
- g_val = g[t, head_id] if in_bounds else Float32(0.0)
370
-
371
- s_beta[tid_] = beta_val
372
-
373
- # compute cumsum(g)
374
- # parallel scan within a warp
375
- for i in cutlass.range_constexpr(5):
376
- offset = cutlass.const_expr(1 << i)
377
- lower = cute.arch.shuffle_sync_up(
378
- g_val, offset, mask_and_clamp=0
379
- )
380
- if lane_id >= offset:
381
- g_val += lower
382
-
383
- # store warp sum
384
- if lane_id == 31:
385
- s_g_cu[warp_id_] = g_val
386
- cute.arch.barrier(barrier_id=3, number_of_threads=BT)
387
-
388
- # add warp sum from lower warps
389
- for i in cutlass.range_constexpr(1, BT // 32):
390
- if warp_id_ >= i:
391
- g_val += s_g_cu[i - 1]
392
- cute.arch.barrier(barrier_id=3, number_of_threads=BT)
393
-
394
- # store g_cu to gmem for H and O kernels
395
- if in_bounds:
396
- g_cu[t, head_id] = g_val
397
-
398
- # store g and g_cu to smem for later
399
- s_g_cu[tid_] = g_val
400
- s_g_cu_exp[tid_] = cute.math.exp(g_val) if in_bounds else 0.0
401
-
402
- ##### Phase 2: A = strictLower(beta * kkt * Gamma) #####
455
+ ##### Phase 1: A = strictLower(beta * kkt * Gamma) #####
456
+ # Ab/Abg share one tmem slot across stages. The MMA warp commits
457
+ # tcgen05 groups in program order: KKT_i, W_i, U_i, KKT_{i+1}.
458
+ # Waiting for KKT_i means the previous W/U commits have completed,
459
+ # so the INV warps can safely overwrite Ab/Abg for this iteration.
460
+ # Wait for prep warps to publish beta/gate and for KKT MMA.
461
if warp_id_ == 0:
462
+ cute.arch.mbarrier_wait(prep_mbar + stage_id, parity)
463
cute.arch.mbarrier_wait(mma_kkt_mbar + stage_id, parity)
405
- cute.arch.barrier(barrier_id=1, number_of_threads=128)
464
+ cute.arch.barrier(barrier_id=INV_BAR, number_of_threads=128)
465
_tcgen05.fence_after_thread_sync()
466
467
# tmem 16x256b layout / ldmatrix layout
468
+ beta_row = cute.make_rmem_tensor(2, Float32)
469
+ g_cu_row = cute.make_rmem_tensor(2, Float32)
470
+ for i in cutlass.range_constexpr(2):
471
+ idx = warp_id_ * 16 + i * 8 + (lane_id // 4)
472
+ beta_row[i] = s_beta[idx, stage_id]
473
+ g_cu_row[i] = s_g_cu[idx, stage_id]
474
+
475
# mode0 is 8 rows together
476
# mode1 is top and bottom 8 rows
477
# mode2 is groups of 16 rows
412
- row_coord = (lane_id // 4, None, warp_id_)
413
- s_beta_view = cute.make_tensor(s_beta, (8, 2, 4))
414
- beta_row = s_beta_view[row_coord].load().reshape((1, 2, 1))
415
-
416
- s_g_cu_view = cute.make_tensor(s_g_cu, (8, 2, 4))
417
- g_cu_row = s_g_cu_view[row_coord].load().reshape((1, 2, 1))
478
+ beta_row = beta_row.load().reshape((1, 2, 1))
479
+ g_cu_row = g_cu_row.load().reshape((1, 2, 1))
480
481
# mode0 is 2 consecutive elems
482
# mode1 is top and bottom 8 rows
@@ -429,7 +491,9 @@ class Sm100ChunkUWKernel:
491
# mode2 is top and bottom 8 rows
492
# mode3 is next 16 columns
493
col_coord = (None, lane_id % 4, None, i)
432
- s_g_cu_view = cute.make_tensor(s_g_cu, (2, 4, 2, BT // 16))
494
+ s_g_cu_view = cute.make_tensor(
495
+ s_g_cu[None, stage_id].iterator, (2, 4, 2, BT // 16)
496
+ )
497
g_cu_col = s_g_cu_view[col_coord].load().reshape((2, 1, 2))
498
499
Gamma = cute.math.exp(g_cu_row - g_cu_col, fastmath=True)
@@ -443,29 +507,23 @@ class Sm100ChunkUWKernel:
507
# pack to BF16
508
# CuteDSL doesn't generate cvt.bf16x2.f32 here for some reasons
509
packed = cute.make_rmem_tensor(4, Uint32)
446
- packed[0] = cvt.fp32x2_to_bf16x2(
447
- A_masked[0, 0, 0], A_masked[1, 0, 0]
448
- )
449
- packed[1] = cvt.fp32x2_to_bf16x2(
450
- A_masked[0, 1, 0], A_masked[1, 1, 0]
451
- )
452
- packed[2] = cvt.fp32x2_to_bf16x2(
453
- A_masked[0, 0, 1], A_masked[1, 0, 1]
454
- )
455
- packed[3] = cvt.fp32x2_to_bf16x2(
456
- A_masked[0, 1, 1], A_masked[1, 1, 1]
457
- )
510
+ for j in cutlass.range_constexpr(4):
511
+ packed[j] = cvt.fp32x2_to_bf16x2(
512
+ A_masked[j * 2], A_masked[j * 2 + 1]
513
+ )
514
515
# store to smem
516
cute.copy(
517
stsm_atom,
518
cute.recast_tensor(packed, BFloat16),
463
- sA_ldsm[warp_id_, None, i],
519
+ sA_ldsm[None, (warp_id_, i)],
520
)
521
466
- cute.arch.barrier(barrier_id=1, number_of_threads=128)
522
+ # use sync warp instead of bar.sync because for block-diagonal inverse,
523
+ # each warp reads its own private smem memory.
524
+ cute.arch.sync_warp()
525
468
- ##### Phase 3: matrix inverse #####
526
+ ##### Phase 2: matrix inverse #####
527
# we use Newton-Schulz iterations to compute the inverse
528
# of the four 16x16 diagonal blocks.
529
# Ai_new = 2 Ai - Ai @ M @ Ai
@@ -477,15 +535,6 @@ class Sm100ChunkUWKernel:
535
zeros_f32 = cute.make_rmem_tensor(4, Float32)
536
zeros_f32.fill(0.0)
537
480
- def set_diagonal(A: cute.Tensor, lane_id: Int32):
481
- "Set the diagonal to 1s"
482
- if lane_id % 9 == 0:
483
- A[0] = (A[0] & Uint32(0xFFFF0000)) | Uint32(0x00003F80)
484
- A[3] = (A[3] & Uint32(0xFFFF0000)) | Uint32(0x00003F80)
485
- elif lane_id % 9 == 4:
486
- A[0] = (A[0] & Uint32(0x0000FFFF)) | Uint32(0x3F800000)
487
- A[3] = (A[3] & Uint32(0x0000FFFF)) | Uint32(0x3F800000)
488
-
538
Ai_bf16 = cute.make_rmem_tensor(8, BFloat16)
539
mma_B_bf16 = cute.make_rmem_tensor(8, BFloat16)
540
M_bf16 = cute.make_rmem_tensor(8, BFloat16)
@@ -496,44 +545,60 @@ class Sm100ChunkUWKernel:
545
mma_B = cute.logical_divide(cute.recast_tensor(mma_B_bf16, Uint32), 2)
546
M = cute.logical_divide(cute.recast_tensor(M_bf16, Uint32), 2)
547
548
+ # construct rmem-backed identity matrix
549
+ eye = cute.make_rmem_tensor(4, Uint32)
550
+ eye[0] = Uint32(lane_id % 9 == 0) * Uint32(0x00003F80) + Uint32(
551
+ lane_id % 9 == 4
552
+ ) * Uint32(0x3F800000)
553
+ eye[1] = 0
554
+ eye[2] = 0
555
+ eye[3] = eye[0]
556
+
557
# initial guess: Ai = I-A
500
- cute.copy(ldsm_atom, sA_ldsm[warp_id_, None, warp_id_], Ai_bf16)
558
+ cute.copy(ldsm_atom, sA_ldsm[None, (warp_id_, warp_id_)], Ai_bf16)
559
for i in cutlass.range_constexpr(4):
502
- Ai[i] ^= Uint32(0x80008000) # negate A
503
- set_diagonal(Ai, lane_id)
560
+ Ai[i] = _bf16x2_sub(eye[i], Ai[i])
561
562
# (4, 2)
563
Ai_f32 = cute.logical_divide(cvt.bf16x2_to_fp32x2(Ai), 4)
564
565
# M is holding -(I+A), stay constant throughout the iterations
509
- cute.copy(ldsm_trans_atom, sA_ldsm[warp_id_, None, warp_id_], M_bf16)
510
- set_diagonal(M, lane_id)
566
+ cute.copy(ldsm_trans_atom, sA_ldsm[None, (warp_id_, warp_id_)], M_bf16)
567
for i in cutlass.range_constexpr(4):
512
- M[i] ^= Uint32(0x80008000)
568
+ M[i] = _bf16x2_sub(_bf16x2_neg(eye[i]), M[i])
569
570
# 3 rounds of Newton-Schulz
571
for _ in cutlass.range_constexpr(3):
572
# First MMA: -AiM = Ai @ (-M)
517
- cute.copy(stsm_atom, Ai_bf16, sA_ldsm[warp_id_, None, warp_id_])
573
+ cute.copy(stsm_atom, Ai_bf16, sA_ldsm[None, (warp_id_, warp_id_)])
574
cute.arch.sync_warp()
575
acc[None, 0] = mma_bf16(Ai, M[None, 0], zeros_f32)
576
acc[None, 1] = mma_bf16(Ai, M[None, 1], zeros_f32)
577
Ai_bf16.store(acc.load().to(BFloat16))
578
579
# Second MMA: Ai_new = 2Ai + (-AiM) @ Ai
524
- for j in cutlass.range_constexpr(8):
580
+ for j in cutlass.range(8, vectorize=True):
581
Ai_f32[j] *= 2.0
582
cute.copy(
583
ldsm_trans_atom,
528
- sA_ldsm[warp_id_, None, warp_id_],
584
+ sA_ldsm[None, (warp_id_, warp_id_)],
585
mma_B_bf16,
586
)
587
Ai_f32[None, 0] = mma_bf16(Ai, mma_B[None, 0], Ai_f32[None, 0])
588
Ai_f32[None, 1] = mma_bf16(Ai, mma_B[None, 1], Ai_f32[None, 1])
589
Ai_bf16.store(Ai_f32.load().to(BFloat16))
590
535
- cute.copy(stsm_atom, Ai_bf16, sAi_ldsm[warp_id_, None, warp_id_])
536
- cute.arch.barrier(barrier_id=1, number_of_threads=128)
591
+ cute.copy(stsm_atom, Ai_bf16, sAi_ldsm[None, (warp_id_, warp_id_)])
592
+ store_ab_abg(
593
+ Ai_f32,
594
+ s_beta[None, stage_id],
595
+ s_beta_g[None, stage_id],
596
+ warp_id_,
597
+ lane_id,
598
+ warp_id_,
599
+ Ab_tmem_base,
600
+ )
601
+ cute.arch.barrier(barrier_id=INV_BAR, number_of_threads=128)
602
603
# off-diagonal by 1
604
# given
@@ -544,14 +609,14 @@ class Sm100ChunkUWKernel:
609
# warp1: Ai10 = -Ai11 @ A10 @ Ai00
610
# warp2: Ai21 = -Ai22 @ A21 @ Ai11
611
# warp3: Ai32 = -Ai33 @ A32 @ Ai22
547
- if warp_id_ > 0:
612
+ if warp_id_ >= 1:
613
neg_Ai = cute.make_rmem_tensor(4, Uint32)
614
for i in cutlass.range_constexpr(4):
550
- neg_Ai[i] = Ai[i] ^ Uint32(0x80008000)
615
+ neg_Ai[i] = _bf16x2_neg(Ai[i])
616
617
cute.copy(
618
ldsm_trans_atom,
554
- sA_ldsm[warp_id_, None, warp_id_ - 1],
619
+ sA_ldsm[None, (warp_id_, warp_id_ - 1)],
620
mma_B_bf16,
621
)
622
acc[None, 0] = mma_bf16(neg_Ai, mma_B[None, 0], zeros_f32)
@@ -560,44 +625,52 @@ class Sm100ChunkUWKernel:
625
626
cute.copy(
627
ldsm_trans_atom,
563
- sAi_ldsm[warp_id_ - 1, None, warp_id_ - 1],
628
+ sAi_ldsm[None, (warp_id_ - 1, warp_id_ - 1)],
629
mma_B_bf16,
630
)
631
acc[None, 0] = mma_bf16(Ai, mma_B[None, 0], zeros_f32)
632
acc[None, 1] = mma_bf16(Ai, mma_B[None, 1], zeros_f32)
633
Ai_bf16.store(acc.load().to(BFloat16))
634
+ store_ab_abg(
635
+ acc,
636
+ s_beta[None, stage_id],
637
+ s_beta_g[None, stage_id],
638
+ warp_id_,
639
+ lane_id,
640
+ warp_id_ - 1,
641
+ Ab_tmem_base,
642
+ )
643
cute.copy(
644
stsm_atom,
645
Ai_bf16,
572
- sAi_ldsm[warp_id_, None, warp_id_ - 1],
646
+ sAi_ldsm[None, (warp_id_, warp_id_ - 1)],
647
)
574
- cute.arch.barrier(barrier_id=1, number_of_threads=128)
648
+ cute.arch.barrier(barrier_id=INV_BAR, number_of_threads=128)
649
650
# off-diagonal by 2
577
- # warp0: Ai20 = -Ai22 @ (A20 @ Ai00 + A21 @ Ai10)
578
- # warp1: Ai31 = -Ai33 @ (A31 @ Ai11 + A32 @ Ai21)
579
- if warp_id_ < 2:
651
+ # warp2: Ai20 = -Ai22 @ (A20 @ Ai00 + A21 @ Ai10)
652
+ # warp3: Ai31 = -Ai33 @ (A31 @ Ai11 + A32 @ Ai21)
653
+ if warp_id_ >= 2:
654
+ tile_col = warp_id_ - 2
655
cute.copy(
656
ldsm_atom,
582
- sA_ldsm[warp_id_ + 2, None, warp_id_],
657
+ sA_ldsm[None, (warp_id_, tile_col)],
658
Ai_bf16,
659
)
660
cute.copy(
661
ldsm_trans_atom,
587
- sAi_ldsm[warp_id_, None, warp_id_],
662
+ sAi_ldsm[None, (tile_col, tile_col)],
663
mma_B_bf16,
664
)
665
acc[None, 0] = mma_bf16(Ai, mma_B[None, 0], zeros_f32)
666
acc[None, 1] = mma_bf16(Ai, mma_B[None, 1], zeros_f32)
667
668
cute.copy(
594
- ldsm_atom,
595
- sA_ldsm[warp_id_ + 2, None, warp_id_ + 1],
596
- Ai_bf16,
669
+ ldsm_atom, sA_ldsm[None, (warp_id_, tile_col + 1)], Ai_bf16
670
)
671
cute.copy(
672
ldsm_trans_atom,
600
- sAi_ldsm[warp_id_ + 1, None, warp_id_],
673
+ sAi_ldsm[None, (tile_col + 1, tile_col)],
674
mma_B_bf16,
675
)
676
acc[None, 0] = mma_bf16(Ai, mma_B[None, 0], acc[None, 0])
@@ -605,79 +678,68 @@ class Sm100ChunkUWKernel:
678
679
tmp = cute.make_rmem_tensor(8, BFloat16)
680
tmp.store(acc.load().to(BFloat16))
608
- cute.copy(stsm_atom, tmp, sAi_ldsm[warp_id_ + 2, None, warp_id_])
681
+ cute.copy(stsm_atom, tmp, sAi_ldsm[None, (warp_id_, tile_col)])
682
cute.arch.sync_warp()
683
611
- cute.copy(
612
- ldsm_atom, sAi_ldsm[warp_id_ + 2, None, warp_id_ + 2], Ai_bf16
613
- )
684
+ cute.copy(ldsm_atom, sAi_ldsm[None, (warp_id_, warp_id_)], Ai_bf16)
685
for i in cutlass.range_constexpr(4):
615
- Ai[i] ^= Uint32(0x80008000)
686
+ Ai[i] = _bf16x2_neg(Ai[i])
687
cute.copy(
688
ldsm_trans_atom,
618
- sAi_ldsm[warp_id_ + 2, None, warp_id_],
689
+ sAi_ldsm[None, (warp_id_, tile_col)],
690
mma_B_bf16,
691
)
692
acc[None, 0] = mma_bf16(Ai, mma_B[None, 0], zeros_f32)
693
acc[None, 1] = mma_bf16(Ai, mma_B[None, 1], zeros_f32)
694
tmp.store(acc.load().to(BFloat16))
624
- cute.copy(stsm_atom, tmp, sAi_ldsm[warp_id_ + 2, None, warp_id_])
625
- cute.arch.barrier(barrier_id=1, number_of_threads=128)
695
+ cute.copy(stsm_atom, tmp, sAi_ldsm[None, (warp_id_, tile_col)])
696
+ store_ab_abg(
697
+ acc,
698
+ s_beta[None, stage_id],
699
+ s_beta_g[None, stage_id],
700
+ warp_id_,
701
+ lane_id,
702
+ tile_col,
703
+ Ab_tmem_base,
704
+ )
705
+ cute.arch.barrier(barrier_id=INV_BAR, number_of_threads=128)
706
707
# off-diagonal by 3
628
- # warp0: Ai30 = -Ai33 @ (A30 @ Ai00 + A31 @ Ai10 + A32 @ Ai20)
629
- if warp_id_ == 0:
630
- cute.copy(ldsm_atom, sA_ldsm[3, None, 0], Ai_bf16)
631
- cute.copy(ldsm_trans_atom, sAi_ldsm[0, None, 0], mma_B_bf16)
708
+ # warp3: Ai30 = -Ai33 @ (A30 @ Ai00 + A31 @ Ai10 + A32 @ Ai20)
709
+ if warp_id_ == 3:
710
+ cute.copy(ldsm_atom, sA_ldsm[None, (3, 0)], Ai_bf16)
711
+ cute.copy(ldsm_trans_atom, sAi_ldsm[None, (0, 0)], mma_B_bf16)
712
acc[None, 0] = mma_bf16(Ai, mma_B[None, 0], zeros_f32)
713
acc[None, 1] = mma_bf16(Ai, mma_B[None, 1], zeros_f32)
714
715
for i in cutlass.range_constexpr(1, 3):
636
- cute.copy(ldsm_atom, sA_ldsm[3, None, i], Ai_bf16)
637
- cute.copy(ldsm_trans_atom, sAi_ldsm[i, None, 0], mma_B_bf16)
716
+ cute.copy(ldsm_atom, sA_ldsm[None, (3, i)], Ai_bf16)
717
+ cute.copy(ldsm_trans_atom, sAi_ldsm[None, (i, 0)], mma_B_bf16)
718
acc[None, 0] = mma_bf16(Ai, mma_B[None, 0], acc[None, 0])
719
acc[None, 1] = mma_bf16(Ai, mma_B[None, 1], acc[None, 1])
720
721
tmp = cute.make_rmem_tensor(8, BFloat16)
722
tmp.store(acc.load().to(BFloat16))
643
- cute.copy(stsm_atom, tmp, sAi_ldsm[3, None, 0])
723
+ cute.copy(stsm_atom, tmp, sAi_ldsm[None, (3, 0)])
724
cute.arch.sync_warp()
725
646
- cute.copy(ldsm_atom, sAi_ldsm[3, None, 3], Ai_bf16)
726
+ cute.copy(ldsm_atom, sAi_ldsm[None, (3, 3)], Ai_bf16)
727
for i in cutlass.range_constexpr(4):
648
- Ai[i] ^= Uint32(0x80008000)
649
- cute.copy(ldsm_trans_atom, sAi_ldsm[3, None, 0], mma_B_bf16)
728
+ Ai[i] = _bf16x2_neg(Ai[i])
729
+ cute.copy(ldsm_trans_atom, sAi_ldsm[None, (3, 0)], mma_B_bf16)
730
acc[None, 0] = mma_bf16(Ai, mma_B[None, 0], zeros_f32)
731
acc[None, 1] = mma_bf16(Ai, mma_B[None, 1], zeros_f32)
732
tmp.store(acc.load().to(BFloat16))
653
- cute.copy(stsm_atom, tmp, sAi_ldsm[3, None, 0])
654
-
655
- ##### Phase 4: compute Ab, Abg #####
656
- if warp_id_ == 3:
657
- cute.arch.mbarrier_wait(mma_u_mbar + stage_id, parity ^ 1)
658
- cute.arch.barrier(barrier_id=1, number_of_threads=128)
659
-
660
- for i in cutlass.range_constexpr(BT // 16):
661
- cute.copy(ldsm_atom, sAi_ldsm[warp_id_, None, i], Ai_bf16)
662
-
663
- col_coord = (None, lane_id % 4, None, i)
664
- s_beta_view = cute.make_tensor(s_beta, (2, 4, 2, BT // 16))
665
- beta_col = s_beta_view[col_coord].load().reshape((2, 1, 2))
666
-
667
- s_g_cu_view = cute.make_tensor(s_g_cu_exp, (2, 4, 2, BT // 16))
668
- g_cu_col = s_g_cu_view[col_coord].load().reshape((2, 1, 2))
669
-
670
- Ai_f32 = cvt.bf16x2_to_fp32x2(Ai).load().reshape((2, 2, 2))
671
-
672
- Ab_f32 = Ai_f32 * beta_col
673
- Ab = Ab_f32.to(BFloat16)
674
- Ab_tmem = Ab_tmem_base + (BT // 2) * stage_id + i * 8
675
- _tcgen05.st(warp_id_ * 32, Ab_tmem, "16x128b", 2, Ab)
676
-
677
- Abg_f32 = Ab_f32 * g_cu_col
678
- Abg = Abg_f32.to(BFloat16)
679
- _tcgen05.st(warp_id_ * 32 + 16, Ab_tmem, "16x128b", 2, Abg)
680
-
733
+ cute.copy(stsm_atom, tmp, sAi_ldsm[None, (3, 0)])
734
+ store_ab_abg(
735
+ acc,
736
+ s_beta[None, stage_id],
737
+ s_beta_g[None, stage_id],
738
+ warp_id_,
739
+ lane_id,
740
+ 0,
741
+ Ab_tmem_base,
742
+ )
743
_tcgen05.wait_st()
744
_tcgen05.fence_before_thread_sync()
745
cute.arch.mbarrier_arrive(inv_mbar + stage_id)
@@ -686,14 +748,18 @@ class Sm100ChunkUWKernel:
748
if stage_id == 0:
749
parity ^= 1
750
689
- elif warp_id < 4:
751
+ else:
752
# epi warps
753
stage_id = 0
754
parity = 0
755
756
# ((BT, num_global_chunks), V_dim)
695
- gU_tiles = cute.logical_divide(tmaU[None, head_id, None], (BT, None))
696
- gW_tiles = cute.logical_divide(tmaW[None, head_id, None], (BT, None))
757
+ gU_tiles = cute.logical_divide(
758
+ U_tma.tma_tensor[None, head_id, None], (BT, None)
759
+ )
760
+ gW_tiles = cute.logical_divide(
761
+ W_tma.tma_tensor[None, head_id, None], (BT, None)
762
+ )
763
764
# sW shape: [BT, (64, K_dim/64)]
765
# sW_view shape: [(8, 2), (4, K_dim/64)]
@@ -719,7 +785,7 @@ class Sm100ChunkUWKernel:
785
elif warp_id == 1:
786
with cute.arch.elect_one():
787
cute.arch.cp_async_bulk_wait_group(0, read=True)
722
- cute.arch.barrier(barrier_id=2, number_of_threads=128)
788
+ cute.arch.barrier(barrier_id=EPI_BAR, number_of_threads=128)
789
_tcgen05.fence_after_thread_sync()
790
791
w_f32 = _tcgen05.ld(warp_id * 32 + 16, U_tmem, "16x256b", K_dim // 8)
@@ -729,16 +795,16 @@ class Sm100ChunkUWKernel:
795
cute.copy(stsm_atom, w_bf16, sW_view)
796
797
# wait for U MMA + issue W TMA store
732
- cute.arch.barrier(barrier_id=2, number_of_threads=128)
798
+ cute.arch.barrier(barrier_id=EPI_BAR, number_of_threads=128)
799
fence_before_tma_store()
800
if warp_id == 0:
801
cute.arch.mbarrier_wait(mma_u_mbar + stage_id, parity)
802
elif warp_id == 1:
803
# don't need to commit
804
simple_tma_copy(
739
- W_tma_atom, sW, gW_tiles[(None, global_chunk_id), None]
805
+ W_tma.atom, sW, gW_tiles[(None, global_chunk_id), None]
806
)
741
- cute.arch.barrier(barrier_id=2, number_of_threads=128)
807
+ cute.arch.barrier(barrier_id=EPI_BAR, number_of_threads=128)
808
_tcgen05.fence_after_thread_sync()
809
810
u_f32 = _tcgen05.ld(warp_id * 32, U_tmem, "16x256b", V_dim // 8)
@@ -749,11 +815,11 @@ class Sm100ChunkUWKernel:
815
u_bf16.store(u_f32.to(BFloat16))
816
cute.copy(stsm_atom, u_bf16, sU_view)
817
752
- cute.arch.barrier(barrier_id=2, number_of_threads=128)
818
+ cute.arch.barrier(barrier_id=EPI_BAR, number_of_threads=128)
819
fence_before_tma_store()
820
if warp_id == 1:
821
simple_tma_copy(
756
- U_tma_atom, sU, gU_tiles[(None, global_chunk_id), None]
822
+ U_tma.atom, sU, gU_tiles[(None, global_chunk_id), None]
823
)
824
with cute.arch.elect_one():
825
cute.arch.cp_async_bulk_commit_group()
vllm/model_executor/layers/mamba/ops/gdn_chunk_cutedsl/kernel_o.py
+82
-80
@@ -61,13 +61,12 @@ class Sm100ChunkOKernel:
61
stride=(64, 0, (1, self.BT * 64), self.BT * dim),
62
)
63
slayout = cute.make_composed_layout(swizzle_128B, 0, slayout)
64
- atom, tma_tensor = cpasync.make_tiled_tma_atom(
64
+ return cpasync.make_tiled_tma_atom(
65
op,
66
cute.logical_divide(tensor, (None, None, 64)),
67
slayout,
68
cta_tiler=(self.BT, 1, dim),
69
)
70
- return atom, tma_tensor, slayout
70
71
@cute.jit
72
def _make_h_tma_args(
@@ -79,17 +78,22 @@ class Sm100ChunkOKernel:
78
num_elems = 128 // (tensor.element_type.width // 8)
79
swizzle_128B = cute.make_swizzle(3, 4, 3)
80
slayout = cute.make_layout(
82
- (1, self.V_dim, (num_elems, self.K_dim // num_elems), stages),
83
- stride=(0, num_elems, (1, self.V_dim * num_elems), self.V_dim * self.K_dim),
81
+ (1, 1, self.V_dim, (num_elems, self.K_dim // num_elems), stages),
82
+ stride=(
83
+ 0,
84
+ 0,
85
+ num_elems,
86
+ (1, self.V_dim * num_elems),
87
+ self.V_dim * self.K_dim,
88
+ ),
89
)
90
slayout = cute.make_composed_layout(swizzle_128B, 0, slayout)
86
- atom, tma_tensor = cpasync.make_tiled_tma_atom(
91
+ return cpasync.make_tiled_tma_atom(
92
op,
88
- cute.logical_divide(tensor, (None, None, num_elems)),
93
+ cute.logical_divide(tensor, (None, None, None, num_elems)),
94
slayout,
90
- cta_tiler=(1, self.V_dim, self.K_dim),
95
+ cta_tiler=(1, 1, self.V_dim, self.K_dim),
96
)
92
- return atom, tma_tensor, slayout
97
98
@cute.jit
99
def __call__(
@@ -111,35 +115,35 @@ class Sm100ChunkOKernel:
115
block = (self.num_warps * 32, 1, 1)
116
tma_g2s = cpasync.CopyBulkTensorTileG2SOp()
117
tma_s2g = cpasync.CopyBulkTensorTileS2GOp()
114
- Q_args = self._make_bf16_tma_args(q, self.K_dim, tma_g2s, self.num_stages)
115
- K_args = self._make_bf16_tma_args(k, self.K_dim, tma_g2s, self.num_stages)
116
- V_args = self._make_bf16_tma_args(
118
+ Q_tma = self._make_bf16_tma_args(q, self.K_dim, tma_g2s, self.num_stages)
119
+ K_tma = self._make_bf16_tma_args(k, self.K_dim, tma_g2s, self.num_stages)
120
+ V_tma = self._make_bf16_tma_args(
121
v_new_chunks, self.V_dim, tma_g2s, self.num_stages
122
)
119
- H_args = self._make_h_tma_args(h, tma_g2s, self.num_stages)
120
- O_args = self._make_bf16_tma_args(o, self.V_dim, tma_s2g, 1)
123
+ H_tma = self._make_h_tma_args(h, tma_g2s, self.num_stages)
124
+ O_tma = self._make_bf16_tma_args(o, self.V_dim, tma_s2g, 1)
125
self.kernel(
122
- Q_args,
123
- K_args,
124
- V_args,
125
- H_args,
126
- O_args,
126
+ Q_tma,
127
+ K_tma,
128
+ V_tma,
129
+ H_tma,
130
+ O_tma,
131
g_cu,
132
o,
133
cu_seqlens,
134
chunk_indices,
135
total_chunks,
136
scale,
133
- ).launch(grid=grid, block=block, stream=stream)
137
+ ).launch(grid=grid, block=block, min_blocks_per_mp=1, stream=stream)
138
139
@cute.kernel
140
def kernel(
141
self,
138
- Q_args: tuple[cute.CopyAtom, cute.Tensor, cute.ComposedLayout],
139
- K_args: tuple[cute.CopyAtom, cute.Tensor, cute.ComposedLayout],
140
- V_args: tuple[cute.CopyAtom, cute.Tensor, cute.ComposedLayout],
141
- H_args: tuple[cute.CopyAtom, cute.Tensor, cute.ComposedLayout],
142
- O_args: tuple[cute.CopyAtom, cute.Tensor, cute.ComposedLayout],
142
+ Q_tma: cpasync.TmaInfo,
143
+ K_tma: cpasync.TmaInfo,
144
+ V_tma: cpasync.TmaInfo,
145
+ H_tma: cpasync.TmaInfo,
146
+ O_tma: cpasync.TmaInfo,
147
g_cu: cute.Tensor,
148
o: cute.Tensor,
149
cu_seqlens: cute.Tensor,
@@ -162,23 +166,17 @@ class Sm100ChunkOKernel:
166
k_head_id = v_head_id // heads_per_qk
167
num_global_chunks = total_chunks[0]
168
165
- Q_tma_atom, tmaQ, sQ_layout = Q_args
166
- K_tma_atom, tmaK, sK_layout = K_args
167
- V_tma_atom, tmaV, sV_layout = V_args
168
- H_tma_atom, tmaH, sH_layout = H_args
169
- O_tma_atom, tmaO, sO_layout = O_args
170
-
169
def allocate_tensor(smem, dtype, layout):
170
return smem.allocate_tensor(
171
dtype, layout.outer, byte_alignment=128, swizzle=layout.inner
172
)
173
174
smem = cutlass.utils.SmemAllocator()
177
- sQ = allocate_tensor(smem, BFloat16, sQ_layout)[None, 0, None, None]
178
- sK = allocate_tensor(smem, BFloat16, sK_layout)[None, 0, None, None]
179
- sV = allocate_tensor(smem, BFloat16, sV_layout)[None, 0, None, None]
180
- sH = allocate_tensor(smem, BFloat16, sH_layout)[0, None, None, None]
181
- sO = allocate_tensor(smem, BFloat16, sO_layout)[None, 0, None, 0]
175
+ sQ = allocate_tensor(smem, BFloat16, Q_tma.smem_layout)[None, 0, None, None]
176
+ sK = allocate_tensor(smem, BFloat16, K_tma.smem_layout)[None, 0, None, None]
177
+ sV = allocate_tensor(smem, BFloat16, V_tma.smem_layout)[None, 0, None, None]
178
+ sH = allocate_tensor(smem, BFloat16, H_tma.smem_layout)[0, 0, None, None, None]
179
+ sO = allocate_tensor(smem, BFloat16, O_tma.smem_layout)[None, 0, None, 0]
180
181
s_g_cu = smem.allocate_array(Float32, BT)
182
qk_full_mbar = smem.allocate_array(Int64, num_stages)
@@ -207,10 +205,10 @@ class Sm100ChunkOKernel:
205
cute.arch.mbarrier_init(epi_mbar, 128)
206
cute.arch.mbarrier_init_fence()
207
elif warp_id == 9:
210
- cpasync.prefetch_descriptor(Q_tma_atom)
211
- cpasync.prefetch_descriptor(K_tma_atom)
212
- cpasync.prefetch_descriptor(V_tma_atom)
213
- cpasync.prefetch_descriptor(H_tma_atom)
208
+ cpasync.prefetch_descriptor(Q_tma.atom)
209
+ cpasync.prefetch_descriptor(K_tma.atom)
210
+ cpasync.prefetch_descriptor(V_tma.atom)
211
+ cpasync.prefetch_descriptor(H_tma.atom)
212
cute.arch.sync_threads()
213
214
if warp_id == 9:
@@ -225,12 +223,16 @@ class Sm100ChunkOKernel:
223
224
# copy Q and K
225
q_tile = cute.local_tile(
228
- cute.domain_offset((bos, 0), tmaQ[None, k_head_id, None]),
226
+ cute.domain_offset(
227
+ (bos, 0), Q_tma.tma_tensor[None, k_head_id, None]
228
+ ),
229
tiler=(BT, K_dim),
230
coord=(chunk_id, 0),
231
)
232
k_tile = cute.local_tile(
233
- cute.domain_offset((bos, 0), tmaK[None, k_head_id, None]),
233
+ cute.domain_offset(
234
+ (bos, 0), K_tma.tma_tensor[None, k_head_id, None]
235
+ ),
236
tiler=(BT, K_dim),
237
coord=(chunk_id, 0),
238
)
@@ -241,13 +243,13 @@ class Sm100ChunkOKernel:
243
with cute.arch.elect_one():
244
STAGE_SIZE = BT * (K_dim + K_dim) * 2
245
cute.arch.mbarrier_arrive_and_expect_tx(mbar, STAGE_SIZE)
244
- simple_tma_copy(Q_tma_atom, q_tile, sQ[None, None, stage_id], mbar)
245
- simple_tma_copy(K_tma_atom, k_tile, sK[None, None, stage_id], mbar)
246
+ simple_tma_copy(Q_tma.atom, q_tile, sQ[None, None, stage_id], mbar)
247
+ simple_tma_copy(K_tma.atom, k_tile, sK[None, None, stage_id], mbar)
248
249
# copy H and V
248
- gH = tmaH[global_chunk_id * self.Hv + v_head_id, None, None]
250
+ gH = H_tma.tma_tensor[global_chunk_id, v_head_id, None, None]
251
gV = cute.local_tile(
250
- tmaV[None, v_head_id, None],
252
+ V_tma.tma_tensor[None, v_head_id, None],
253
tiler=(BT, V_dim),
254
coord=(global_chunk_id, 0),
255
)
@@ -262,10 +264,10 @@ class Sm100ChunkOKernel:
264
mbar, H_STAGE_SIZE + V_STAGE_SIZE
265
)
266
simple_tma_copy(
265
- H_tma_atom, gH, sH[None, None, stage_id], mbar, EVICT_FIRST
267
+ H_tma.atom, gH, sH[None, None, stage_id], mbar, EVICT_FIRST
268
)
269
simple_tma_copy(
268
- V_tma_atom, gV, sV[None, None, stage_id], mbar, EVICT_FIRST
270
+ V_tma.atom, gV, sV[None, None, stage_id], mbar, EVICT_FIRST
271
)
272
273
stage_id = (stage_id + 1) % num_stages
@@ -302,40 +304,37 @@ class Sm100ChunkOKernel:
304
cute.arch.mbarrier_wait(qk_full_mbar + stage_id, tma_parity)
305
_tcgen05.fence_after_thread_sync()
306
305
- with cute.arch.elect_one():
306
- for i in cutlass.range_constexpr(K_dim // BT):
307
- for j in cutlass.range_constexpr(BT // 16):
308
- qdesc = qdesc_base | ((i * BT * 128 + j * 32) >> 4)
309
- kdesc = kdesc_base | ((i * BT * 128 + j * 32) >> 4)
310
- _tcgen05.mma_f16(
311
- qk_tmem, qdesc, kdesc, qk_idesc, (i > 0) or (j > 0)
312
- )
313
- _tcgen05.commit(qk_mbar)
307
+ for i in cutlass.range_constexpr(K_dim // 64):
308
+ for j in cutlass.range_constexpr(64 // 16):
309
+ qdesc = qdesc_base | ((i * BT * 128 + j * 32) >> 4)
310
+ kdesc = kdesc_base | ((i * BT * 128 + j * 32) >> 4)
311
+ _tcgen05.mma_f16(
312
+ qk_tmem, qdesc, kdesc, qk_idesc, (i > 0) or (j > 0)
313
+ )
314
+ _tcgen05.commit(qk_mbar)
315
316
##### 2nd MMA: Q @ H.T #####
317
cute.arch.mbarrier_wait(hv_full_mbar + stage_id, tma_parity)
318
_tcgen05.fence_after_thread_sync()
318
- with cute.arch.elect_one():
319
- for i in cutlass.range_constexpr(K_dim // BT):
320
- for j in cutlass.range_constexpr(BT // 16):
321
- qdesc = qdesc_base | ((i * BT * 128 + j * 32) >> 4)
322
- hdesc = hdesc_base | ((i * V_dim * 128 + j * 32) >> 4)
323
- _tcgen05.mma_f16(
324
- qh_tmem, qdesc, hdesc, qh_idesc, (i > 0) or (j > 0)
325
- )
326
- _tcgen05.commit(qk_empty_mbar + stage_id)
319
+ for i in cutlass.range_constexpr(K_dim // 64):
320
+ for j in cutlass.range_constexpr(64 // 16):
321
+ qdesc = qdesc_base | ((i * BT * 128 + j * 32) >> 4)
322
+ hdesc = hdesc_base | ((i * V_dim * 128 + j * 32) >> 4)
323
+ _tcgen05.mma_f16(
324
+ qh_tmem, qdesc, hdesc, qh_idesc, (i > 0) or (j > 0)
325
+ )
326
+ _tcgen05.commit(qk_empty_mbar + stage_id)
327
328
##### 3rd MMA: P @ V #####
329
# stalled by mask(QK)
330
cute.arch.mbarrier_wait(mask_mbar, mask_parity)
331
_tcgen05.fence_after_thread_sync()
332
- with cute.arch.elect_one():
333
- for i in cutlass.range_constexpr(BT // 16):
334
- vdesc = vdesc_base | ((i * 16 * 128) >> 4)
335
- _tcgen05.mma_ts_f16(
336
- out_tmem, p_tmem + i * 8, vdesc, pv_idesc, i > 0
337
- )
338
- _tcgen05.commit(pv_mma_mbar + stage_id)
332
+ for i in cutlass.range_constexpr(BT // 16):
333
+ vdesc = vdesc_base | ((i * 16 * 128) >> 4)
334
+ _tcgen05.mma_ts_f16(
335
+ out_tmem, p_tmem + i * 8, vdesc, pv_idesc, i > 0
336
+ )
337
+ _tcgen05.commit(pv_mma_mbar + stage_id)
338
339
stage_id = (stage_id + 1) % num_stages
340
if stage_id == 0:
@@ -499,11 +498,13 @@ class Sm100ChunkOKernel:
498
fence_before_tma_store()
499
if warp_id == 3:
500
gO = cute.local_tile(
502
- cute.domain_offset((bos, 0), tmaO[None, v_head_id, None]),
501
+ cute.domain_offset(
502
+ (bos, 0), O_tma.tma_tensor[None, v_head_id, None]
503
+ ),
504
tiler=(BT, V_dim),
505
coord=(chunk_id, 0),
506
)
506
- simple_tma_copy(O_tma_atom, sO, gO)
507
+ simple_tma_copy(O_tma.atom, sO, gO)
508
with cute.arch.elect_one():
509
cute.arch.cp_async_bulk_commit_group()
510
@@ -559,13 +560,14 @@ class Sm100ChunkOKernel:
560
total_t = cute.sym_int()
561
pad_t = cute.sym_int()
562
total_chunks_n = cute.sym_int()
562
- h_outer_n = cute.sym_int()
563
cu_entries = cute.sym_int()
564
565
q = make_fake_tensor(BFloat16, (total_t, H, K_dim), divisibility=16)
566
k = make_fake_tensor(BFloat16, (total_t, H, K_dim), divisibility=16)
567
v_new = make_fake_tensor(BFloat16, (pad_t, Hv, V_dim), divisibility=16)
568
- h_flat = make_fake_tensor(BFloat16, (h_outer_n, V_dim, K_dim), divisibility=16)
568
+ h = make_fake_tensor(
569
+ BFloat16, (total_chunks_n, Hv, V_dim, K_dim), divisibility=16
570
+ )
571
g_cu = make_fake_tensor(Float32, (total_t, Hv), divisibility=4)
572
o = make_fake_tensor(BFloat16, (total_t, Hv, V_dim), divisibility=16)
573
cu_seqlens = make_fake_tensor(Int32, (cu_entries,), divisibility=1)
@@ -586,7 +588,7 @@ class Sm100ChunkOKernel:
588
q,
589
k,
590
v_new,
589
- h_flat,
591
+ h,
592
g_cu,
593
o,
594
cu_seqlens,
@@ -602,7 +604,7 @@ class Sm100ChunkOKernel:
604
def o_cutedsl(
605
q: torch.Tensor,
606
k: torch.Tensor,
605
- v_new_chunks: torch.Tensor,
607
+ v_new: torch.Tensor,
608
h: torch.Tensor,
609
g_cu: torch.Tensor,
610
o: torch.Tensor,
@@ -618,8 +620,8 @@ def o_cutedsl(
620
Sm100ChunkOKernel.compile(H, Hv, K_dim, V_dim)(
621
q,
622
k,
621
- v_new_chunks.view(-1, Hv, V_dim),
622
- h.view(-1, V_dim, K_dim),
623
+ v_new,
624
+ h,
625
g_cu,
626
o,
627
cu_seqlens,