1use super::*;
11
12#[allow(clippy::too_many_arguments)]
19pub fn moe_gate_topk_fused(
20 gpu: &dyn GpuBackend,
21 kernel: KernelHandle,
22 input: DevicePtr,
23 gate_weight: &QuantizedWeight,
24 expert_indices: DevicePtr,
25 expert_weights: DevicePtr,
26 num_experts: u32,
27 k: u32,
28 top_k: u32,
29 normalize: u32,
30 stream: u64,
31) -> Result<()> {
32 let smem_bytes = k as usize * 2;
33 KernelLaunch::new(gpu, kernel)
34 .grid([1, 1, 1])
35 .block([256, 1, 1])
36 .shared_mem(smem_bytes as u32)
37 .arg_ptr(input)
38 .arg_ptr(gate_weight.weight)
39 .arg_ptr(gate_weight.weight_scale)
40 .arg_f32(gate_weight.weight_scale_2)
41 .arg_ptr(expert_indices)
42 .arg_ptr(expert_weights)
43 .arg_u32(num_experts)
44 .arg_u32(k)
45 .arg_u32(top_k)
46 .arg_u32(normalize)
47 .launch(stream)
48}
49
50#[allow(clippy::too_many_arguments)]
65pub fn moe_build_tile_worklist(
66 gpu: &dyn GpuBackend,
67 kernel: KernelHandle,
68 expert_offsets: DevicePtr,
69 weight_ptrs: DevicePtr,
70 worklist: DevicePtr,
71 total_tiles: DevicePtr,
72 num_experts: u32,
73 n_tiles: u32,
74 m_tile: u32,
75 stream: u64,
76) -> Result<()> {
77 KernelLaunch::new(gpu, kernel)
78 .grid([1, 1, 1])
79 .block([256, 1, 1])
80 .arg_ptr(expert_offsets)
81 .arg_ptr(weight_ptrs)
82 .arg_ptr(worklist)
83 .arg_ptr(total_tiles)
84 .arg_u32(num_experts)
85 .arg_u32(n_tiles)
86 .arg_u32(m_tile)
87 .launch(stream)
88}
89
90#[allow(clippy::too_many_arguments)]
104pub fn moe_fp8_grouped_gemm(
105 gpu: &dyn GpuBackend,
106 kernel: KernelHandle,
107 input: DevicePtr,
108 weight_ptrs: DevicePtr,
109 scale_ptrs: DevicePtr,
110 output: DevicePtr,
111 expert_offsets: DevicePtr,
112 sorted_token_ids: DevicePtr,
113 num_experts: u32,
114 n: u32,
115 k: u32,
116 worklist: DevicePtr,
117 total_tiles: DevicePtr,
118 max_tiles: u32,
119 stream: u64,
120) -> Result<()> {
121 const MAX_GRID_CTAS: u32 = 16384;
122 let grid_ctas = max_tiles.clamp(1, MAX_GRID_CTAS);
123 #[cfg(metrale_hip)]
128 let block = [512u32, 1, 1];
129 #[cfg(not(metrale_hip))]
130 let block = [256u32, 1, 1];
131 KernelLaunch::new(gpu, kernel)
132 .grid([grid_ctas, 1, 1])
133 .block(block)
134 .arg_ptr(input)
135 .arg_ptr(weight_ptrs)
136 .arg_ptr(scale_ptrs)
137 .arg_ptr(output)
138 .arg_ptr(expert_offsets)
139 .arg_ptr(sorted_token_ids)
140 .arg_u32(num_experts)
141 .arg_u32(n)
142 .arg_u32(k)
143 .arg_ptr(worklist)
144 .arg_ptr(total_tiles)
145 .launch(stream)
146}
147
148#[allow(clippy::too_many_arguments)]
156pub fn moe_w8a8_grouped_gemm(
157 gpu: &dyn GpuBackend,
158 kernel: KernelHandle,
159 a_fp8: DevicePtr,
160 a_scale: DevicePtr,
161 weight_ptrs: DevicePtr,
162 scale_ptrs: DevicePtr,
163 output: DevicePtr,
164 expert_offsets: DevicePtr,
165 sorted_token_ids: DevicePtr,
166 num_experts: u32,
167 n: u32,
168 k: u32,
169 max_m_tiles: u32,
170 stream: u64,
171) -> Result<()> {
172 KernelLaunch::new(gpu, kernel)
173 .grid([div_ceil(n, 64), max_m_tiles, num_experts])
174 .block([128, 1, 1])
175 .arg_ptr(a_fp8)
176 .arg_ptr(a_scale)
177 .arg_ptr(weight_ptrs)
178 .arg_ptr(scale_ptrs)
179 .arg_ptr(output)
180 .arg_ptr(expert_offsets)
181 .arg_ptr(sorted_token_ids)
182 .arg_u32(num_experts)
183 .arg_u32(n)
184 .arg_u32(k)
185 .launch(stream)
186}
187
188#[allow(clippy::too_many_arguments)]
193pub fn moe_w8a8_grouped_gemm_pm4(
194 gpu: &dyn GpuBackend,
195 kernel: KernelHandle,
196 a_fp8: DevicePtr,
197 a_scale: DevicePtr,
198 weight_ptrs: DevicePtr,
199 scale_ptrs: DevicePtr,
200 output: DevicePtr,
201 expert_offsets: DevicePtr,
202 sorted_token_ids: DevicePtr,
203 num_experts: u32,
204 n: u32,
205 k: u32,
206 worklist: DevicePtr,
207 total_tiles: DevicePtr,
208 max_tiles: u32,
209 stream: u64,
210) -> Result<()> {
211 const MAX_GRID_CTAS: u32 = 16384;
212 let grid_ctas = max_tiles.clamp(1, MAX_GRID_CTAS);
213 KernelLaunch::new(gpu, kernel)
216 .grid([grid_ctas, 1, 1])
217 .block([256, 1, 1])
218 .arg_ptr(a_fp8)
219 .arg_ptr(a_scale)
220 .arg_ptr(weight_ptrs)
221 .arg_ptr(scale_ptrs)
222 .arg_ptr(output)
223 .arg_ptr(expert_offsets)
224 .arg_ptr(sorted_token_ids)
225 .arg_u32(num_experts)
226 .arg_u32(n)
227 .arg_u32(k)
228 .arg_ptr(worklist)
229 .arg_ptr(total_tiles)
230 .launch(stream)
231}
232
233#[derive(Clone, Copy, Debug, PartialEq, Eq)]
237pub struct MoeE4m3Tile {
238 pub m_tile: u32,
239 pub n_tile: u32,
240 pub smem_bytes: u32,
241 pub ctas_per_sm: u32,
242}
243
244impl MoeE4m3Tile {
245 const fn new(m_tile: u32, n_tile: u32) -> Self {
247 Self {
248 m_tile,
249 n_tile,
250 smem_bytes: 3 * (m_tile + n_tile) * 64 + 3 * m_tile * 4 + m_tile * 4,
251 ctas_per_sm: 2,
252 }
253 }
254
255 pub fn fits(&self, n: u32, k: u32) -> bool {
258 n > 0 && k > 0 && n.is_multiple_of(self.n_tile) && k.is_multiple_of(128)
259 }
260}
261
262pub const MOE_E4M3_GU: MoeE4m3Tile = MoeE4m3Tile::new(64, 128);
264pub const MOE_E4M3_DN: MoeE4m3Tile = MoeE4m3Tile::new(128, 64);
266
267#[allow(clippy::too_many_arguments)]
272pub fn moe_w8a8_grouped_gemm_e4m3(
273 gpu: &dyn GpuBackend,
274 kernel: KernelHandle,
275 tile: MoeE4m3Tile,
276 a_fp8: DevicePtr,
277 a_scale: DevicePtr,
278 weight_ptrs: DevicePtr,
279 scale_ptrs: DevicePtr,
280 output: DevicePtr,
281 expert_offsets: DevicePtr,
282 sorted_token_ids: DevicePtr,
283 n: u32,
284 k: u32,
285 worklist: DevicePtr,
286 total_tiles: DevicePtr,
287 grid_ctas: u32,
288 stream: u64,
289) -> Result<()> {
290 anyhow::ensure!(
291 tile.fits(n, k),
292 "moe_w8a8_grouped_gemm_e4m3: N={n} K={k} does not fit {tile:?}"
293 );
294 KernelLaunch::new(gpu, kernel)
295 .grid([grid_ctas.clamp(1, 16384), 1, 1])
296 .block([256, 1, 1])
297 .shared_mem(tile.smem_bytes)
298 .arg_ptr(a_fp8)
299 .arg_ptr(a_scale)
300 .arg_ptr(weight_ptrs)
301 .arg_ptr(scale_ptrs)
302 .arg_ptr(output)
303 .arg_ptr(expert_offsets)
304 .arg_ptr(sorted_token_ids)
305 .arg_u32(n)
306 .arg_u32(k)
307 .arg_ptr(worklist)
308 .arg_ptr(total_tiles)
309 .launch(stream)
310}
311
312#[allow(clippy::too_many_arguments)]
318pub fn moe_w8a8_gateup_silu_e4m3(
319 gpu: &dyn GpuBackend,
320 kernel: KernelHandle,
321 a_fp8: DevicePtr,
322 a_scale: DevicePtr,
323 gate: (DevicePtr, DevicePtr),
324 up: (DevicePtr, DevicePtr),
325 out_fp8: DevicePtr,
326 out_scale: DevicePtr,
327 expert_offsets: DevicePtr,
328 sorted_token_ids: DevicePtr,
329 n: u32,
330 k: u32,
331 worklist: DevicePtr,
332 total_tiles: DevicePtr,
333 grid_ctas: u32,
334 stream: u64,
335) -> Result<()> {
336 anyhow::ensure!(
337 MOE_E4M3_GU.fits(n, k),
338 "moe_w8a8_gateup_silu_e4m3: N={n} K={k} does not fit {MOE_E4M3_GU:?}"
339 );
340 KernelLaunch::new(gpu, kernel)
341 .grid([grid_ctas.clamp(1, 16384), 1, 1])
342 .block([256, 1, 1])
343 .shared_mem(MOE_E4M3_GU.smem_bytes)
344 .arg_ptr(a_fp8)
345 .arg_ptr(a_scale)
346 .arg_ptr(gate.0)
347 .arg_ptr(gate.1)
348 .arg_ptr(up.0)
349 .arg_ptr(up.1)
350 .arg_ptr(out_fp8)
351 .arg_ptr(out_scale)
352 .arg_ptr(expert_offsets)
353 .arg_ptr(sorted_token_ids)
354 .arg_u32(n)
355 .arg_u32(k)
356 .arg_ptr(worklist)
357 .arg_ptr(total_tiles)
358 .launch(stream)
359}
360
361#[allow(clippy::too_many_arguments)]
368pub fn moe_bf16_grouped_gemm(
369 gpu: &dyn GpuBackend,
370 kernel: KernelHandle,
371 input: DevicePtr,
372 weight_ptrs: DevicePtr,
373 output: DevicePtr,
374 expert_offsets: DevicePtr,
375 sorted_token_ids: DevicePtr,
376 num_experts: u32,
377 n: u32,
378 k: u32,
379 max_m_tiles: u32,
380 stream: u64,
381) -> Result<()> {
382 KernelLaunch::new(gpu, kernel)
383 .grid([div_ceil(n, 64), max_m_tiles, num_experts])
384 .block([128, 1, 1])
385 .arg_ptr(input)
386 .arg_ptr(weight_ptrs)
387 .arg_ptr(output)
388 .arg_ptr(expert_offsets)
389 .arg_ptr(sorted_token_ids)
390 .arg_u32(num_experts)
391 .arg_u32(n)
392 .arg_u32(k)
393 .launch(stream)
394}