metrale_model_layers/layers/ops/
gemm_quant_w8a16.rs1use super::*;
13
14#[allow(clippy::too_many_arguments)]
21pub fn w8a16_gemv(
22 gpu: &dyn GpuBackend,
23 kernel: KernelHandle,
24 input: DevicePtr,
25 weight: DevicePtr,
26 row_scale: DevicePtr,
27 output: DevicePtr,
28 n: u32,
29 k: u32,
30 stream: u64,
31) -> Result<()> {
32 KernelLaunch::new(gpu, kernel)
33 .grid([div_ceil(n, 4), 1, 1])
34 .block([256, 1, 1])
35 .arg_ptr(input)
36 .arg_ptr(weight)
37 .arg_ptr(row_scale)
38 .arg_ptr(output)
39 .arg_u32(n)
40 .arg_u32(k)
41 .launch(stream)
42}
43
44#[allow(clippy::too_many_arguments)]
47pub fn w8a16_gemm(
48 gpu: &dyn GpuBackend,
49 kernel: KernelHandle,
50 input: DevicePtr,
51 weight: DevicePtr,
52 block_scale: DevicePtr,
53 output: DevicePtr,
54 m: u32,
55 n: u32,
56 k: u32,
57 stream: u64,
58) -> Result<()> {
59 #[cfg(metrale_hip)]
64 let (grid, block) = ([div_ceil(n, 128), div_ceil(m, 256), 1], [512, 1, 1]);
65 #[cfg(not(metrale_hip))]
66 let (grid, block) = ([div_ceil(n, 64), div_ceil(m, 64), 1], [128, 1, 1]);
67 KernelLaunch::new(gpu, kernel)
68 .grid(grid)
69 .block(block)
70 .arg_ptr(input)
71 .arg_ptr(weight)
72 .arg_ptr(block_scale)
73 .arg_ptr(output)
74 .arg_u32(m)
75 .arg_u32(n)
76 .arg_u32(k)
77 .launch(stream)
78}
79
80#[allow(clippy::too_many_arguments)]
85pub fn w8a16_gemm_pipelined(
86 gpu: &dyn GpuBackend,
87 kernel: KernelHandle,
88 input: DevicePtr,
89 weight: DevicePtr,
90 block_scale: DevicePtr,
91 output: DevicePtr,
92 m: u32,
93 n: u32,
94 k: u32,
95 stream: u64,
96) -> Result<()> {
97 if let Some(twin) = w8a16_pipe128_kernel(gpu, m, n, k)? {
98 return KernelLaunch::new(gpu, twin)
101 .grid([n / 128, div_ceil(m, 128), 1])
102 .block([256, 1, 1])
103 .shared_mem(3 * (8192 + 4096) + 2 * 8192 + 1024)
104 .arg_ptr(input)
105 .arg_ptr(weight)
106 .arg_ptr(block_scale)
107 .arg_ptr(output)
108 .arg_u32(m)
109 .arg_u32(n)
110 .arg_u32(k)
111 .launch(stream);
112 }
113 KernelLaunch::new(gpu, kernel)
114 .grid([div_ceil(n, 32), div_ceil(m, 128), 1])
115 .block([256, 1, 1])
116 .arg_ptr(input)
117 .arg_ptr(weight)
118 .arg_ptr(block_scale)
119 .arg_ptr(output)
120 .arg_u32(m)
121 .arg_u32(n)
122 .arg_u32(k)
123 .launch(stream)
124}
125
126pub const W8A16_PIPE128_MIN_ROWS: u32 = 256;
129
130fn w8a16_pipe128_kernel(
137 gpu: &dyn GpuBackend,
138 m: u32,
139 n: u32,
140 k: u32,
141) -> Result<Option<KernelHandle>> {
142 const MODULE: &str = "w8a16_gemm_pipe128";
143 static OFF: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
144 let off = *OFF.get_or_init(|| std::env::var_os("METRALE_NO_W8A16_PIPE128").is_some());
145 if off
146 || m < W8A16_PIPE128_MIN_ROWS
147 || n == 0
148 || !n.is_multiple_of(128)
149 || k == 0
150 || !k.is_multiple_of(128)
151 || !gpu.has_module(MODULE)
152 {
153 return Ok(None);
154 }
155 Ok(Some(gpu.op_cache().kernel(
156 gpu,
157 MODULE,
158 "w8a16_gemm_pipe128",
159 )?))
160}
161
162#[allow(clippy::too_many_arguments)]
167pub fn w8a16_gemm_t(
168 gpu: &dyn GpuBackend,
169 kernel: KernelHandle,
170 input: DevicePtr,
171 weight_t: DevicePtr, block_scale_t: DevicePtr, output: DevicePtr,
174 m: u32,
175 n: u32,
176 k: u32,
177 stream: u64,
178) -> Result<()> {
179 KernelLaunch::new(gpu, kernel)
180 .grid([div_ceil(n, 64), div_ceil(m, 64), 1])
181 .block([128, 1, 1])
182 .arg_ptr(input)
183 .arg_ptr(weight_t)
184 .arg_ptr(block_scale_t)
185 .arg_ptr(output)
186 .arg_u32(m)
187 .arg_u32(n)
188 .arg_u32(k)
189 .launch(stream)
190}
191
192#[allow(clippy::too_many_arguments)]
198pub fn w8a16_gemm_n128_m128(
199 gpu: &dyn GpuBackend,
200 kernel: KernelHandle,
201 input: DevicePtr,
202 weight_t: DevicePtr, block_scale_t: DevicePtr, output: DevicePtr,
205 m: u32,
206 n: u32,
207 k: u32,
208 stream: u64,
209) -> Result<()> {
210 super::super::log_gemm_shape(gpu, "w8a16_gemm_t_m128", m, n, k);
211 KernelLaunch::new(gpu, kernel)
212 .grid([div_ceil(n, 128), div_ceil(m, 128), 1])
213 .block([256, 1, 1])
214 .arg_ptr(input)
215 .arg_ptr(weight_t)
216 .arg_ptr(block_scale_t)
217 .arg_ptr(output)
218 .arg_u32(m)
219 .arg_u32(n)
220 .arg_u32(k)
221 .launch(stream)
222}
223
224#[allow(clippy::too_many_arguments)]
228pub fn w8a16_gemm_t_pipelined(
229 gpu: &dyn GpuBackend,
230 kernel: KernelHandle,
231 input: DevicePtr,
232 weight_t: DevicePtr,
233 block_scale_t: DevicePtr,
234 output: DevicePtr,
235 m: u32,
236 n: u32,
237 k: u32,
238 stream: u64,
239) -> Result<()> {
240 super::super::log_gemm_shape(gpu, "w8a16_gemm_t_pipelined", m, n, k);
241 KernelLaunch::new(gpu, kernel)
242 .grid([div_ceil(n, 32), div_ceil(m, 128), 1])
243 .block([256, 1, 1])
244 .arg_ptr(input)
245 .arg_ptr(weight_t)
246 .arg_ptr(block_scale_t)
247 .arg_ptr(output)
248 .arg_u32(m)
249 .arg_u32(n)
250 .arg_u32(k)
251 .launch(stream)
252}
253
254#[allow(clippy::too_many_arguments)]
260pub fn w8a16_gemv_row_tiered(
261 gpu: &dyn GpuBackend,
262 gemv_kernel: KernelHandle,
263 m32_kernel: KernelHandle,
264 input: DevicePtr,
265 weight: DevicePtr,
266 block_scale: DevicePtr,
267 output: DevicePtr,
268 n: u32,
269 k: u32,
270 stream: u64,
271) -> Result<()> {
272 if crate::layers::row_tiers() == crate::layers::RowTiers::Canonical
273 && super::w8a16_pipelined_prefers_m32(1, k, m32_kernel)
274 {
275 return super::w8a16_gemm_pipelined_m32(
276 gpu,
277 m32_kernel,
278 input,
279 weight,
280 block_scale,
281 output,
282 1,
283 n,
284 k,
285 stream,
286 );
287 }
288 w8a16_gemv(
289 gpu,
290 gemv_kernel,
291 input,
292 weight,
293 block_scale,
294 output,
295 n,
296 k,
297 stream,
298 )
299}