1use anyhow::{Result, ensure};
14use metrale_gpu_runtime::gpu::{DevicePtr, GpuBackend, KernelHandle};
15use metrale_gpu_runtime::kernel_args::{KernelLaunch, div_ceil};
16
17use crate::weight_map::Fp8DenseWeight;
18
19#[allow(clippy::too_many_arguments)]
26pub fn fp8_gemv_rowscale_batch8_rt2(
27 gpu: &dyn GpuBackend,
28 kernel: KernelHandle,
29 input: DevicePtr,
30 weight: &Fp8DenseWeight,
31 output: DevicePtr,
32 m: u32,
33 n: u32,
34 k: u32,
35 stream: u64,
36) -> Result<()> {
37 ensure!(
38 (1..=8).contains(&m),
39 "fp8_gemv_rowscale_batch8_rt2: m={m} outside 1..=8 (kernel MAX_M)"
40 );
41 ensure!(
42 k.is_multiple_of(16),
43 "fp8_gemv_rowscale_batch8_rt2: K={k} not a multiple of 16"
44 );
45 KernelLaunch::new(gpu, kernel)
46 .grid([div_ceil(n, 8), 1, 1])
47 .block([256, 1, 1])
48 .arg_ptr(input)
49 .arg_ptr(weight.weight)
50 .arg_ptr(weight.row_scale)
51 .arg_ptr(output)
52 .arg_u32(m)
53 .arg_u32(n)
54 .arg_u32(k)
55 .launch(stream)
56}
57
58#[allow(clippy::too_many_arguments)]
63pub fn fp8_gemv_rowscale_batch16_rt2(
64 gpu: &dyn GpuBackend,
65 kernel: KernelHandle,
66 input: DevicePtr,
67 weight: &Fp8DenseWeight,
68 output: DevicePtr,
69 m: u32,
70 n: u32,
71 k: u32,
72 stream: u64,
73) -> Result<()> {
74 ensure!(
75 (1..=16).contains(&m),
76 "fp8_gemv_rowscale_batch16_rt2: m={m} outside 1..=16 (kernel MAX_M)"
77 );
78 ensure!(
79 k.is_multiple_of(16),
80 "fp8_gemv_rowscale_batch16_rt2: K={k} not a multiple of 16"
81 );
82 KernelLaunch::new(gpu, kernel)
83 .grid([div_ceil(n, 8), 1, 1])
84 .block([256, 1, 1])
85 .arg_ptr(input)
86 .arg_ptr(weight.weight)
87 .arg_ptr(weight.row_scale)
88 .arg_ptr(output)
89 .arg_u32(m)
90 .arg_u32(n)
91 .arg_u32(k)
92 .launch(stream)
93}
94
95pub fn dense_gemv_fp8w_batch2(
101 gpu: &dyn GpuBackend,
102 kernel: KernelHandle,
103 input: DevicePtr,
104 weight: &Fp8DenseWeight,
105 output: DevicePtr,
106 n: u32,
107 k: u32,
108 stream: u64,
109) -> Result<()> {
110 KernelLaunch::new(gpu, kernel)
111 .grid([div_ceil(n, 4), 1, 1])
112 .block([256, 1, 1])
113 .arg_ptr(input)
114 .arg_ptr(weight.weight)
115 .arg_ptr(weight.row_scale)
116 .arg_ptr(output)
117 .arg_u32(n)
118 .arg_u32(k)
119 .launch(stream)
120}
121
122pub type ContiguousBatchGemv = fn(
126 &dyn GpuBackend,
127 KernelHandle,
128 DevicePtr,
129 DevicePtr,
130 DevicePtr,
131 DevicePtr,
132 u32,
133 u32,
134 u32,
135 u64,
136) -> Result<()>;
137
138#[allow(clippy::too_many_arguments)]
151pub fn w8a16_gemv_batch4(
152 gpu: &dyn GpuBackend,
153 kernel: KernelHandle,
154 input: DevicePtr,
155 weight: DevicePtr,
156 block_scale: DevicePtr,
157 output: DevicePtr,
158 m: u32,
159 n: u32,
160 k: u32,
161 stream: u64,
162) -> Result<()> {
163 ensure!(
164 (1..=4).contains(&m),
165 "w8a16_gemv_batch4: m={m} outside 1..=4 (kernel MAX_M; use w8a16_gemv_batch16)"
166 );
167 contiguous_batch_launch(
168 gpu,
169 kernel,
170 input,
171 weight,
172 block_scale,
173 output,
174 m,
175 n,
176 k,
177 stream,
178 )
179}
180
181#[allow(clippy::too_many_arguments)]
185pub fn w8a16_gemv_batch16(
186 gpu: &dyn GpuBackend,
187 kernel: KernelHandle,
188 input: DevicePtr,
189 weight: DevicePtr,
190 block_scale: DevicePtr,
191 output: DevicePtr,
192 m: u32,
193 n: u32,
194 k: u32,
195 stream: u64,
196) -> Result<()> {
197 ensure!(
198 (1..=16).contains(&m),
199 "w8a16_gemv_batch16: m={m} outside 1..=16 (kernel MAX_M)"
200 );
201 contiguous_batch_launch(
202 gpu,
203 kernel,
204 input,
205 weight,
206 block_scale,
207 output,
208 m,
209 n,
210 k,
211 stream,
212 )
213}
214
215#[allow(clippy::too_many_arguments)]
218fn contiguous_batch_launch(
219 gpu: &dyn GpuBackend,
220 kernel: KernelHandle,
221 input: DevicePtr,
222 weight: DevicePtr,
223 block_scale: DevicePtr,
224 output: DevicePtr,
225 m: u32,
226 n: u32,
227 k: u32,
228 stream: u64,
229) -> Result<()> {
230 KernelLaunch::new(gpu, kernel)
231 .grid([div_ceil(n, 4), 1, 1])
232 .block([256, 1, 1])
233 .arg_ptr(input)
234 .arg_ptr(weight)
235 .arg_ptr(block_scale)
236 .arg_ptr(output)
237 .arg_u32(m)
238 .arg_u32(n)
239 .arg_u32(k)
240 .launch(stream)
241}
242
243#[allow(clippy::too_many_arguments)]
246pub fn w8a16_gemv_batch2(
247 gpu: &dyn GpuBackend,
248 kernel: KernelHandle,
249 input: DevicePtr,
250 weight: DevicePtr,
251 block_scale: DevicePtr,
252 output: DevicePtr,
253 n: u32,
254 k: u32,
255 stream: u64,
256) -> Result<()> {
257 KernelLaunch::new(gpu, kernel)
258 .grid([div_ceil(n, 4), 1, 1])
259 .block([256, 1, 1])
260 .arg_ptr(input)
261 .arg_ptr(weight)
262 .arg_ptr(block_scale)
263 .arg_ptr(output)
264 .arg_u32(n)
265 .arg_u32(k)
266 .launch(stream)
267}
268
269#[allow(clippy::too_many_arguments)]
287pub fn w8a16_gemv_batch4_strided(
288 gpu: &dyn GpuBackend,
289 kernel: KernelHandle,
290 input: DevicePtr,
291 weight: DevicePtr,
292 block_scale: DevicePtr,
293 output: DevicePtr,
294 m: u32,
295 n: u32,
296 k: u32,
297 a_row_stride: u32,
298 c_row_stride: u32,
299 stream: u64,
300) -> Result<()> {
301 ensure!(
302 (1..=4).contains(&m),
303 "w8a16_gemv_batch4_strided: m={m} outside 1..=4 (kernel MAX_M)"
304 );
305 strided_batch_launch(
306 gpu,
307 kernel,
308 input,
309 weight,
310 block_scale,
311 output,
312 m,
313 n,
314 k,
315 a_row_stride,
316 c_row_stride,
317 stream,
318 )
319}
320
321#[allow(clippy::too_many_arguments)]
325pub fn w8a16_gemv_batch16_strided(
326 gpu: &dyn GpuBackend,
327 kernel: KernelHandle,
328 input: DevicePtr,
329 weight: DevicePtr,
330 block_scale: DevicePtr,
331 output: DevicePtr,
332 m: u32,
333 n: u32,
334 k: u32,
335 a_row_stride: u32,
336 c_row_stride: u32,
337 stream: u64,
338) -> Result<()> {
339 ensure!(
340 (1..=16).contains(&m),
341 "w8a16_gemv_batch16_strided: m={m} outside 1..=16 (kernel MAX_M)"
342 );
343 strided_batch_launch(
344 gpu,
345 kernel,
346 input,
347 weight,
348 block_scale,
349 output,
350 m,
351 n,
352 k,
353 a_row_stride,
354 c_row_stride,
355 stream,
356 )
357}
358
359#[allow(clippy::too_many_arguments)]
362fn strided_batch_launch(
363 gpu: &dyn GpuBackend,
364 kernel: KernelHandle,
365 input: DevicePtr,
366 weight: DevicePtr,
367 block_scale: DevicePtr,
368 output: DevicePtr,
369 m: u32,
370 n: u32,
371 k: u32,
372 a_row_stride: u32,
373 c_row_stride: u32,
374 stream: u64,
375) -> Result<()> {
376 ensure!(
377 a_row_stride >= k && c_row_stride >= n,
378 "w8a16_gemv batch strided: row pitches (a={a_row_stride}, c={c_row_stride}) \
379 must cover the used extents (k={k}, n={n})"
380 );
381 ensure!(
382 a_row_stride.is_multiple_of(8),
383 "w8a16_gemv batch strided: a_row_stride={a_row_stride} must keep rows \
384 16B-aligned (uint4 activation loads)"
385 );
386 KernelLaunch::new(gpu, kernel)
387 .grid([div_ceil(n, 4), 1, 1])
388 .block([256, 1, 1])
389 .arg_ptr(input)
390 .arg_ptr(weight)
391 .arg_ptr(block_scale)
392 .arg_ptr(output)
393 .arg_u32(m)
394 .arg_u32(n)
395 .arg_u32(k)
396 .arg_u32(a_row_stride)
397 .arg_u32(c_row_stride)
398 .launch(stream)
399}