metrale_model_layers/layers/ops/
q4k_mmq.rs1use anyhow::Result;
16use metrale_gpu_runtime::gpu::{DevicePtr, GpuBackend, KernelHandle};
17use metrale_gpu_runtime::kernel_args::{KernelLaunch, div_ceil};
18
19pub const QK_K: u32 = 256;
21pub const Q4K_BLOCK_BYTES: usize = 144;
23pub const Q4K_MMQ_SMEM: u32 = 57856;
28const CUDA_QUANTIZE_BLOCK_SIZE_MMQ: u32 = 128;
29
30pub fn q4k_weight_bytes(nrows: u32, n_per_row: u32) -> usize {
33 (nrows as usize) * (n_per_row as usize / QK_K as usize) * Q4K_BLOCK_BYTES
34}
35
36pub fn q8_1_scratch_bytes(m: u32, k: u32) -> usize {
41 let kpad = div_ceil(k, QK_K) * QK_K;
42 (m as usize) * (kpad as usize) * 4 + (1 << 20)
43}
44
45pub fn dequant_nvfp4_to_bf16(
48 gpu: &dyn GpuBackend,
49 kernel: KernelHandle,
50 packed: DevicePtr,
51 scales: DevicePtr,
52 out_bf16: DevicePtr,
53 scale2: f32,
54 n: u32,
55 k: u32,
56 stream: u64,
57) -> Result<()> {
58 KernelLaunch::new(gpu, kernel)
59 .grid([n, 1, 1])
60 .block([256, 1, 1])
61 .arg_ptr(packed)
62 .arg_ptr(scales)
63 .arg_ptr(out_bf16)
64 .arg_f32(scale2)
65 .arg_u32(n)
66 .arg_u32(k)
67 .launch(stream)
68}
69
70pub fn quantize_weight_q4k(
73 gpu: &dyn GpuBackend,
74 kernel: KernelHandle,
75 input_bf16: DevicePtr,
76 out_q4k: DevicePtr,
77 nrows: u32,
78 n_per_row: u32,
79 stream: u64,
80) -> Result<()> {
81 let total_sb = (nrows as u64) * (n_per_row as u64 / QK_K as u64);
82 let grid_x = div_ceil(total_sb as u32, 128);
83 KernelLaunch::new(gpu, kernel)
84 .grid([grid_x, 1, 1])
85 .block([128, 1, 1])
86 .arg_ptr(input_bf16)
87 .arg_ptr(out_q4k)
88 .arg_u32(nrows)
89 .arg_u32(n_per_row)
90 .launch(stream)
91}
92
93pub fn quantize_act_q8_1(
96 gpu: &dyn GpuBackend,
97 kernel: KernelHandle,
98 input_bf16: DevicePtr,
99 out_q8: DevicePtr,
100 m: u32,
101 k: u32,
102 stream: u64,
103) -> Result<()> {
104 let kpad = div_ceil(k, QK_K) * QK_K;
105 let grid_y = div_ceil(kpad, 4 * CUDA_QUANTIZE_BLOCK_SIZE_MMQ);
106 KernelLaunch::new(gpu, kernel)
107 .grid([m, grid_y, 1])
108 .block([CUDA_QUANTIZE_BLOCK_SIZE_MMQ, 1, 1])
109 .arg_ptr(input_bf16)
110 .arg_ptr(out_q8)
111 .arg_u64(k as u64)
112 .arg_u64(k as u64)
113 .arg_u64(kpad as u64)
114 .arg_u32(m)
115 .launch(stream)
116}
117
118pub fn q4k_mmq_gemm(
122 gpu: &dyn GpuBackend,
123 kernel_nc: KernelHandle,
124 kernel_wc: KernelHandle,
125 a_q8: DevicePtr,
126 w_q4k: DevicePtr,
127 out_bf16: DevicePtr,
128 m: u32,
129 n: u32,
130 k: u32,
131 stream: u64,
132) -> Result<()> {
133 let kernel = if !n.is_multiple_of(128) {
134 kernel_wc
135 } else {
136 kernel_nc
137 };
138 KernelLaunch::new(gpu, kernel)
139 .grid([div_ceil(n, 128), div_ceil(m, 128), 1])
140 .block([32, 8, 1])
141 .shared_mem(Q4K_MMQ_SMEM)
142 .arg_ptr(w_q4k)
143 .arg_ptr(a_q8)
144 .arg_ptr(out_bf16)
145 .arg_u32(n)
146 .arg_u32(m)
147 .arg_u32(k)
148 .arg_u32(k / QK_K)
149 .arg_u32(m)
150 .arg_u32(n)
151 .launch(stream)
152}