1#![allow(unused_imports)]
11
12use anyhow::Result;
13use metrale_gpu_runtime::gpu::{DevicePtr, GpuBackend, KernelHandle};
14use metrale_gpu_runtime::kernel_args::{KernelLaunch, div_ceil};
15
16use crate::layers::moe;
17use crate::weight_map::{DenseWeight, Fp8DenseWeight, Fp8Weight, QuantizedWeight};
18
19use super::*;
20
21#[allow(clippy::too_many_arguments)]
24pub fn quant_gemv(
25 gpu: &dyn GpuBackend,
26 gemv_nvfp4: KernelHandle,
27 gemv_fp8: KernelHandle,
28 gemv_dense: KernelHandle,
29 input: DevicePtr,
30 weight: &crate::weight_map::QuantWeight,
31 output: DevicePtr,
32 n: u32,
33 k: u32,
34 stream: u64,
35) -> Result<()> {
36 use crate::weight_map::QuantWeight;
37 match weight {
38 QuantWeight::Nvfp4(w) => w4a16_gemv(gpu, gemv_nvfp4, input, w, output, n, k, stream),
39 QuantWeight::Fp8(w) => w8a16_gemv(
40 gpu,
41 gemv_fp8,
42 input,
43 w.weight,
44 w.row_scale,
45 output,
46 n,
47 k,
48 stream,
49 ),
50 QuantWeight::Dense(w) => dense_gemv(gpu, gemv_dense, input, w, output, n, k, stream),
51 QuantWeight::PackedQ2(_) => anyhow::bail!(
54 "quant_gemv: PackedQ2 not routed through the generic dispatcher; use q2_0_gemv_vec"
55 ),
56 }
57}
58
59#[allow(clippy::too_many_arguments)]
62pub fn quant_gemm(
63 gpu: &dyn GpuBackend,
64 gemm_nvfp4: KernelHandle,
65 gemm_fp8: KernelHandle,
66 gemm_dense: KernelHandle,
67 input: DevicePtr,
68 weight: &crate::weight_map::QuantWeight,
69 output: DevicePtr,
70 m: u32,
71 n: u32,
72 k: u32,
73 stream: u64,
74) -> Result<()> {
75 use crate::weight_map::QuantWeight;
76 match weight {
77 QuantWeight::Nvfp4(w) => w4a16_gemm(gpu, gemm_nvfp4, input, w, output, m, n, k, stream),
78 QuantWeight::Fp8(w) => w8a16_gemm(
79 gpu,
80 gemm_fp8,
81 input,
82 w.weight,
83 w.row_scale,
84 output,
85 m,
86 n,
87 k,
88 stream,
89 ),
90 QuantWeight::Dense(w) => dense_gemm(gpu, gemm_dense, input, w, output, m, n, k, stream),
91 QuantWeight::PackedQ2(_) => anyhow::bail!(
92 "quant_gemm: PackedQ2 not routed through the generic dispatcher; \
93 use the layer's transient-dequant prefill path"
94 ),
95 }
96}
97
98pub fn w4a16_gemv(
101 gpu: &dyn GpuBackend,
102 kernel: KernelHandle,
103 input: DevicePtr,
104 weight: &QuantizedWeight,
105 output: DevicePtr,
106 n: u32,
107 k: u32,
108 stream: u64,
109) -> Result<()> {
110 KernelLaunch::new(gpu, kernel)
111 .grid([w4a16_gemv_grid_x(n), 1, 1])
112 .block([256, 1, 1])
113 .arg_ptr(input)
114 .arg_ptr(weight.weight)
115 .arg_ptr(weight.weight_scale)
116 .arg_f32(weight.weight_scale_2)
117 .arg_ptr(output)
118 .arg_u32(n)
119 .arg_u32(k)
120 .launch(stream)
121}
122
123pub fn w4a16_gemv_batch2(
127 gpu: &dyn GpuBackend,
128 kernel: KernelHandle,
129 input: DevicePtr,
130 weight: &QuantizedWeight,
131 output: DevicePtr,
132 n: u32,
133 k: u32,
134 stream: u64,
135) -> Result<()> {
136 if super::gemv_tc::tc_fixed_m(gpu, input, weight, output, 2, n, k, stream)? {
137 return Ok(());
138 }
139 KernelLaunch::new(gpu, kernel)
140 .grid([div_ceil(n, 4), 1, 1])
141 .block([256, 1, 1])
142 .arg_ptr(input)
143 .arg_ptr(weight.weight)
144 .arg_ptr(weight.weight_scale)
145 .arg_f32(weight.weight_scale_2)
146 .arg_ptr(output)
147 .arg_u32(n)
148 .arg_u32(k)
149 .launch(stream)
150}
151
152pub fn w4a16_gemv_batch3(
154 gpu: &dyn GpuBackend,
155 kernel: KernelHandle,
156 input: DevicePtr,
157 weight: &QuantizedWeight,
158 output: DevicePtr,
159 n: u32,
160 k: u32,
161 stream: u64,
162) -> Result<()> {
163 if super::gemv_tc::tc_fixed_m(gpu, input, weight, output, 3, n, k, stream)? {
164 return Ok(());
165 }
166 KernelLaunch::new(gpu, kernel)
167 .grid([div_ceil(n, 4), 1, 1])
168 .block([256, 1, 1])
169 .arg_ptr(input)
170 .arg_ptr(weight.weight)
171 .arg_ptr(weight.weight_scale)
172 .arg_f32(weight.weight_scale_2)
173 .arg_ptr(output)
174 .arg_u32(n)
175 .arg_u32(k)
176 .launch(stream)
177}
178
179pub fn w4a16_gemv_batchm(
184 gpu: &dyn GpuBackend,
185 kernel: KernelHandle,
186 input: DevicePtr,
187 weight: &QuantizedWeight,
188 output: DevicePtr,
189 m: u32,
190 n: u32,
191 k: u32,
192 stream: u64,
193) -> Result<()> {
194 anyhow::ensure!(m <= 32, "w4a16_gemv_batchm caps at M=32 (batch32; m={m})");
200 let (kernel, grid_x, block_x) = match super::gemv_tc::tc_kernel(gpu, m, n, k) {
203 Some((tc, grid_x)) => (tc, grid_x, super::gemv_tc::TC_BLOCK),
204 None => (kernel, div_ceil(n, 4), 256),
205 };
206 KernelLaunch::new(gpu, kernel)
207 .grid([grid_x, 1, 1])
208 .block([block_x, 1, 1])
209 .arg_ptr(input)
210 .arg_ptr(weight.weight)
211 .arg_ptr(weight.weight_scale)
212 .arg_f32(weight.weight_scale_2)
213 .arg_ptr(output)
214 .arg_u32(m)
215 .arg_u32(n)
216 .arg_u32(k)
217 .launch(stream)
218}
219
220#[allow(clippy::too_many_arguments)]
224pub fn w4a16_gemv_qg(
225 gpu: &dyn GpuBackend,
226 kernel: KernelHandle,
227 input: DevicePtr,
228 weight: &QuantizedWeight,
229 output: DevicePtr,
230 n: u32,
231 k: u32,
232 num_heads: u32,
233 head_dim: u32,
234 stream: u64,
235) -> Result<()> {
236 KernelLaunch::new(gpu, kernel)
237 .grid([div_ceil(n, 4), 1, 1])
238 .block([256, 1, 1])
239 .arg_ptr(input)
240 .arg_ptr(weight.weight)
241 .arg_ptr(weight.weight_scale)
242 .arg_f32(weight.weight_scale_2)
243 .arg_ptr(output)
244 .arg_u32(n)
245 .arg_u32(k)
246 .arg_u32(num_heads)
247 .arg_u32(head_dim)
248 .launch(stream)
249}
250
251#[allow(clippy::too_many_arguments)]
254pub fn w4a16_gemv_qkvz(
255 gpu: &dyn GpuBackend,
256 kernel: KernelHandle,
257 input: DevicePtr,
258 weight: &QuantizedWeight,
259 output: DevicePtr,
260 n: u32,
261 k: u32,
262 num_groups: u32,
263 head_k_dim: u32,
264 vheads_per_group: u32,
265 head_v_dim: u32,
266 stream: u64,
267) -> Result<()> {
268 KernelLaunch::new(gpu, kernel)
269 .grid([div_ceil(n, 4), 1, 1])
270 .block([256, 1, 1])
271 .arg_ptr(input)
272 .arg_ptr(weight.weight)
273 .arg_ptr(weight.weight_scale)
274 .arg_f32(weight.weight_scale_2)
275 .arg_ptr(output)
276 .arg_u32(n)
277 .arg_u32(k)
278 .arg_u32(num_groups)
279 .arg_u32(head_k_dim)
280 .arg_u32(vheads_per_group)
281 .arg_u32(head_v_dim)
282 .launch(stream)
283}
284
285#[allow(clippy::too_many_arguments)]
288pub fn w4a16_gemv_qg_batch2(
289 gpu: &dyn GpuBackend,
290 kernel: KernelHandle,
291 input: DevicePtr,
292 weight: &QuantizedWeight,
293 output: DevicePtr,
294 n: u32,
295 k: u32,
296 num_heads: u32,
297 head_dim: u32,
298 stream: u64,
299) -> Result<()> {
300 KernelLaunch::new(gpu, kernel)
301 .grid([div_ceil(n, 4), 1, 1])
302 .block([256, 1, 1])
303 .arg_ptr(input)
304 .arg_ptr(weight.weight)
305 .arg_ptr(weight.weight_scale)
306 .arg_f32(weight.weight_scale_2)
307 .arg_ptr(output)
308 .arg_u32(n)
309 .arg_u32(k)
310 .arg_u32(num_heads)
311 .arg_u32(head_dim)
312 .launch(stream)
313}
314
315#[allow(clippy::too_many_arguments)]
318pub fn w4a16_gemv_qg_batch3(
319 gpu: &dyn GpuBackend,
320 kernel: KernelHandle,
321 input: DevicePtr,
322 weight: &QuantizedWeight,
323 output: DevicePtr,
324 n: u32,
325 k: u32,
326 num_heads: u32,
327 head_dim: u32,
328 stream: u64,
329) -> Result<()> {
330 KernelLaunch::new(gpu, kernel)
331 .grid([div_ceil(n, 4), 1, 1])
332 .block([256, 1, 1])
333 .arg_ptr(input)
334 .arg_ptr(weight.weight)
335 .arg_ptr(weight.weight_scale)
336 .arg_f32(weight.weight_scale_2)
337 .arg_ptr(output)
338 .arg_u32(n)
339 .arg_u32(k)
340 .arg_u32(num_heads)
341 .arg_u32(head_dim)
342 .launch(stream)
343}
344
345#[allow(clippy::too_many_arguments)]
348pub fn w4a16_gemv_dual_batch3(
349 gpu: &dyn GpuBackend,
350 kernel: KernelHandle,
351 input: DevicePtr,
352 weight0: &QuantizedWeight,
353 output0: DevicePtr,
354 weight1: &QuantizedWeight,
355 output1: DevicePtr,
356 n: u32,
357 k: u32,
358 stream: u64,
359) -> Result<()> {
360 if super::gemv_tc::tc_fixed_m(gpu, input, weight0, output0, 3, n, k, stream)? {
364 super::gemv_tc::tc_fixed_m(gpu, input, weight1, output1, 3, n, k, stream)?;
365 return Ok(());
366 }
367 KernelLaunch::new(gpu, kernel)
368 .grid([div_ceil(n, 4), 1, 2])
369 .block([256, 1, 1])
370 .arg_ptr(input)
371 .arg_ptr(weight0.weight)
372 .arg_ptr(weight0.weight_scale)
373 .arg_f32(weight0.weight_scale_2)
374 .arg_ptr(output0)
375 .arg_ptr(weight1.weight)
376 .arg_ptr(weight1.weight_scale)
377 .arg_f32(weight1.weight_scale_2)
378 .arg_ptr(output1)
379 .arg_u32(n)
380 .arg_u32(k)
381 .launch(stream)
382}
383
384#[allow(clippy::too_many_arguments)]
386pub fn w4a16_gemv_dual_batch2(
387 gpu: &dyn GpuBackend,
388 kernel: KernelHandle,
389 input: DevicePtr,
390 weight0: &QuantizedWeight,
391 output0: DevicePtr,
392 weight1: &QuantizedWeight,
393 output1: DevicePtr,
394 n: u32,
395 k: u32,
396 stream: u64,
397) -> Result<()> {
398 if super::gemv_tc::tc_fixed_m(gpu, input, weight0, output0, 2, n, k, stream)? {
402 super::gemv_tc::tc_fixed_m(gpu, input, weight1, output1, 2, n, k, stream)?;
403 return Ok(());
404 }
405 KernelLaunch::new(gpu, kernel)
406 .grid([div_ceil(n, 4), 1, 2])
407 .block([256, 1, 1])
408 .arg_ptr(input)
409 .arg_ptr(weight0.weight)
410 .arg_ptr(weight0.weight_scale)
411 .arg_f32(weight0.weight_scale_2)
412 .arg_ptr(output0)
413 .arg_ptr(weight1.weight)
414 .arg_ptr(weight1.weight_scale)
415 .arg_f32(weight1.weight_scale_2)
416 .arg_ptr(output1)
417 .arg_u32(n)
418 .arg_u32(k)
419 .launch(stream)
420}