1use cudarc::driver::{CudaSlice, DevicePtr, DevicePtrMut};
19
20unsafe extern "C" {
21 fn memra_f16_pp_gemm(
23 w_f16: *const core::ffi::c_void,
24 x_f32: *const f32,
25 xh_f16: *mut core::ffi::c_void,
26 y_f32: *mut f32,
27 m: i32,
28 n: i32,
29 k: i32,
30 ws: *mut core::ffi::c_void,
31 ws_bytes: usize,
32 stream: *mut core::ffi::c_void,
33 ) -> i32;
34 fn memra_f16_cvt(
36 x_f32: *const f32,
37 xh_f16: *mut core::ffi::c_void,
38 nelem: usize,
39 stream: *mut core::ffi::c_void,
40 ) -> i32;
41 fn memra_f16_pp_gemm_pre(
43 w_f16: *const core::ffi::c_void,
44 xh_f16: *const core::ffi::c_void,
45 y_f32: *mut f32,
46 m: i32,
47 n: i32,
48 k: i32,
49 ws: *mut core::ffi::c_void,
50 ws_bytes: usize,
51 stream: *mut core::ffi::c_void,
52 ) -> i32;
53 fn memra_q8_0_dequant_f16(
55 w_q8: *const core::ffi::c_void,
56 w_f16: *mut core::ffi::c_void,
57 out_f: i64,
58 nblk_row: i64,
59 stream: *mut core::ffi::c_void,
60 ) -> i32;
61 fn memra_q4_0_dequant_f16(
63 w_q4: *const core::ffi::c_void,
64 w_f16: *mut core::ffi::c_void,
65 out_f: i64,
66 nblk_row: i64,
67 stream: *mut core::ffi::c_void,
68 ) -> i32;
69 fn memra_q6_K_dequant_f16(
71 w_q6: *const core::ffi::c_void,
72 w_f16: *mut core::ffi::c_void,
73 out_f: i64,
74 nsb_row: i64,
75 stream: *mut core::ffi::c_void,
76 ) -> i32;
77 fn memra_q4_K_dequant_f16(
79 w_q4k: *const core::ffi::c_void,
80 w_f16: *mut core::ffi::c_void,
81 out_f: i64,
82 nsb_row: i64,
83 stream: *mut core::ffi::c_void,
84 ) -> i32;
85 fn memra_q5_K_dequant_f16(
87 w_q5k: *const core::ffi::c_void,
88 w_f16: *mut core::ffi::c_void,
89 out_f: i64,
90 nsb_row: i64,
91 stream: *mut core::ffi::c_void,
92 ) -> i32;
93}
94
95pub fn pp_f16_enabled() -> bool {
101 static ON: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
102 *ON.get_or_init(|| match std::env::var("MEMRA_PP_F16").as_deref() {
103 Ok("1") => true,
104 Ok("0") => false,
105 _ => cfg!(memra_hopper_mma),
106 })
107}
108
109pub fn pp_f16_capacity_ok(free: usize, need: usize) -> bool {
118 if std::env::var("MEMRA_PP_F16").is_ok() {
119 return false; }
121 need > 0 && free >= need + (8usize << 30)
122}
123
124pub struct F16Scratch {
127 pub xh: CudaSlice<u8>,
128 pub ws: CudaSlice<u8>,
129 cap_xh: usize,
130}
131
132impl F16Scratch {
133 pub fn with_capacity(
136 e: &crate::Engine,
137 xh_bytes: usize,
138 ) -> Result<Self, Box<dyn std::error::Error>> {
139 Ok(F16Scratch {
140 xh: e.alloc_u8_uninit(xh_bytes)?,
141 ws: e.alloc_u8_uninit(F16_WS_BYTES)?,
142 cap_xh: xh_bytes,
143 })
144 }
145}
146
147const F16_WS_BYTES: usize = 64 << 20;
148
149impl crate::Engine {
150 pub fn f16_scratch_swap(&self, new: Option<F16Scratch>) -> Option<F16Scratch> {
153 std::mem::replace(&mut *self.f16_scratch.lock().unwrap(), new)
154 }
155
156 pub fn try_f16_gemm(
159 &self,
160 w: &crate::model::GpuTensor,
161 x: &CudaSlice<f32>,
162 m: usize,
163 ) -> Result<Option<CudaSlice<f32>>, Box<dyn std::error::Error>> {
164 use crate::model::GpuTensor;
165 let (w16, ne, scale) = match w {
166 GpuTensor::Quant {
167 f16: Some(w16),
168 ne,
169 scale,
170 ..
171 } => (w16, ne, *scale),
172 _ => return Ok(None),
173 };
174 let (in_f, out_f) = (ne[0] as usize, ne[1] as usize);
175 static SIM_ACT: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
180 let sim_act =
181 *SIM_ACT.get_or_init(|| std::env::var("MEMRA_W8A8_SIM").as_deref() == Ok("2"));
182 let mut y = if sim_act {
183 let mut hx = self.dtoh(x)?;
184 hx.truncate(m * in_f);
185 for row in hx.chunks_mut(in_f) {
186 let amax = row.iter().fold(0f32, |a, &v| a.max(v.abs()));
187 if amax > 0.0 {
188 let d = amax / 127.0;
189 for v in row.iter_mut() {
190 *v = (*v / d).round().clamp(-127.0, 127.0) * d;
191 }
192 }
193 }
194 let xq = self.htod(&hx)?;
195 self.qmatvec_gemm_f16_raw(w16, &xq, m, in_f, out_f)?
196 } else {
197 self.qmatvec_gemm_f16_raw(w16, x, m, in_f, out_f)?
198 };
199 if scale != 1.0 {
200 self.scale_inplace(&mut y, scale, m * out_f)?;
201 }
202 Ok(Some(y))
203 }
204
205 pub fn qmatvec_gemm_f16_raw(
207 &self,
208 w16: &CudaSlice<u8>,
209 x: &CudaSlice<f32>,
210 m: usize,
211 in_f: usize,
212 out_f: usize,
213 ) -> Result<CudaSlice<f32>, Box<dyn std::error::Error>> {
214 let need_xh = m * in_f * 2;
215 let mut guard = self.f16_scratch.lock().unwrap();
216 if guard.is_none() {
217 *guard = Some(F16Scratch {
218 xh: self.alloc_u8_uninit(need_xh)?,
219 ws: self.alloc_u8_uninit(F16_WS_BYTES)?,
220 cap_xh: need_xh,
221 });
222 }
223 let s = guard.as_mut().unwrap();
224 if need_xh > s.cap_xh {
225 s.xh = self.alloc_u8_uninit(need_xh)?;
226 s.cap_xh = need_xh;
227 }
228 let mut y = self.uninit(m * out_f)?; let rc = {
230 let stream = self.gpu.stream();
231 let (w_p, _gw) = w16.device_ptr(&stream);
232 let (x_p, _gx) = x.device_ptr(&stream);
233 let (h_p, _gh) = s.xh.device_ptr_mut(&stream);
234 let (y_p, _gy) = y.device_ptr_mut(&stream);
235 let (ws_p, _gws) = s.ws.device_ptr_mut(&stream);
236 unsafe {
237 memra_f16_pp_gemm(
238 w_p as *const core::ffi::c_void,
239 x_p as *const f32,
240 h_p as *mut core::ffi::c_void,
241 y_p as *mut f32,
242 m as i32,
243 out_f as i32,
244 in_f as i32,
245 ws_p as *mut core::ffi::c_void,
246 F16_WS_BYTES,
247 stream.cu_stream() as *mut core::ffi::c_void,
248 )
249 }
250 };
251 if rc != 0 {
252 return Err(format!(
253 "memra_f16_pp_gemm rc={rc} (m={m} n={out_f} k={in_f}; 1xxxx=cudaError convert, \
254 2xxxx=no cublasLt algo, 3xxxx=matmul status)"
255 )
256 .into());
257 }
258 Ok(y)
259 }
260
261 pub fn f16_act(
265 &self,
266 x: &CudaSlice<f32>,
267 nelem: usize,
268 in_f: usize,
269 ) -> Result<CudaSlice<u8>, Box<dyn std::error::Error>> {
270 static SIM_ACT2: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
274 if *SIM_ACT2.get_or_init(|| std::env::var("MEMRA_W8A8_SIM").as_deref() == Ok("2"))
275 && in_f > 0
276 && nelem % in_f == 0
277 {
278 static ONCE: std::sync::Once = std::sync::Once::new();
279 ONCE.call_once(|| {
280 eprintln!("[w8a8-sim] act per-token int8 fake-quant ACTIVE (f16_act)")
281 });
282 let mut hx = self.dtoh(x)?;
283 hx.truncate(nelem);
284 for row in hx.chunks_mut(in_f) {
285 let amax = row.iter().fold(0f32, |a, &v| a.max(v.abs()));
286 if amax > 0.0 {
287 let d = amax / 127.0;
288 for v in row.iter_mut() {
289 *v = (*v / d).round().clamp(-127.0, 127.0) * d;
290 }
291 }
292 }
293 let xq = self.htod(&hx)?;
294 let mut xh = self.alloc_u8_uninit(nelem * 2)?;
295 let rc = {
296 let stream = self.gpu.stream();
297 let (x_p, _gx) = xq.device_ptr(&stream);
298 let (h_p, _gh) = xh.device_ptr_mut(&stream);
299 unsafe {
300 memra_f16_cvt(
301 x_p as *const f32,
302 h_p as *mut core::ffi::c_void,
303 nelem,
304 stream.cu_stream() as *mut core::ffi::c_void,
305 )
306 }
307 };
308 if rc != 0 {
309 return Err(format!("memra_f16_cvt rc={rc}").into());
310 }
311 return Ok(xh);
312 }
313 let mut xh = self.alloc_u8_uninit(nelem * 2)?;
314 let rc = {
315 let stream = self.gpu.stream();
316 let (x_p, _gx) = x.device_ptr(&stream);
317 let (h_p, _gh) = xh.device_ptr_mut(&stream);
318 unsafe {
319 memra_f16_cvt(
320 x_p as *const f32,
321 h_p as *mut core::ffi::c_void,
322 nelem,
323 stream.cu_stream() as *mut core::ffi::c_void,
324 )
325 }
326 };
327 if rc != 0 {
328 return Err(format!("memra_f16_cvt rc={rc}").into());
329 }
330 Ok(xh)
331 }
332
333 pub fn try_f16_gemm_pre_into(
338 &self,
339 w: &crate::model::GpuTensor,
340 xh: &CudaSlice<u8>,
341 m: usize,
342 y: &mut CudaSlice<f32>,
343 ) -> Result<bool, Box<dyn std::error::Error>> {
344 use crate::model::GpuTensor;
345 let (w16, ne, scale) = match w {
346 GpuTensor::Quant {
347 f16: Some(w16),
348 ne,
349 scale,
350 ..
351 } => (w16, ne, *scale),
352 _ => return Ok(false),
353 };
354 let (in_f, out_f) = (ne[0] as usize, ne[1] as usize);
355 assert!(
356 y.len() >= m * out_f,
357 "try_f16_gemm_pre_into: output slab too small"
358 );
359 let mut guard = self.f16_scratch.lock().unwrap();
360 if guard.is_none() {
361 *guard = Some(F16Scratch {
362 xh: self.alloc_u8_uninit(2)?,
363 ws: self.alloc_u8_uninit(F16_WS_BYTES)?,
364 cap_xh: 2,
365 });
366 }
367 let s = guard.as_mut().unwrap();
368 let rc = {
369 let stream = self.gpu.stream();
370 let (w_p, _gw) = w16.device_ptr(&stream);
371 let (h_p, _gh) = xh.device_ptr(&stream);
372 let (y_p, _gy) = y.device_ptr_mut(&stream);
373 let (ws_p, _gws) = s.ws.device_ptr_mut(&stream);
374 unsafe {
375 memra_f16_pp_gemm_pre(
376 w_p as *const core::ffi::c_void,
377 h_p as *const core::ffi::c_void,
378 y_p as *mut f32,
379 m as i32,
380 out_f as i32,
381 in_f as i32,
382 ws_p as *mut core::ffi::c_void,
383 F16_WS_BYTES,
384 stream.cu_stream() as *mut core::ffi::c_void,
385 )
386 }
387 };
388 if rc != 0 {
389 return Err(
390 format!("memra_f16_pp_gemm_pre(into) rc={rc} (m={m} n={out_f} k={in_f})").into(),
391 );
392 }
393 if scale != 1.0 {
394 self.scale_inplace(y, scale, m * out_f)?;
395 }
396 Ok(true)
397 }
398
399 pub fn try_f16_gemm_pre_into_off(
403 &self,
404 w: &crate::model::GpuTensor,
405 xh: &CudaSlice<u8>,
406 m: usize,
407 y: &mut CudaSlice<f32>,
408 off_elems: usize,
409 ) -> Result<bool, Box<dyn std::error::Error>> {
410 use crate::model::GpuTensor;
411 let (w16, ne, scale) = match w {
412 GpuTensor::Quant {
413 f16: Some(w16),
414 ne,
415 scale,
416 ..
417 } => (w16, ne, *scale),
418 _ => return Ok(false),
419 };
420 let (in_f, out_f) = (ne[0] as usize, ne[1] as usize);
421 assert!(
422 y.len() >= off_elems + m * out_f,
423 "try_f16_gemm_pre_into_off: output slab too small"
424 );
425 if scale != 1.0 {
426 return Ok(false); }
428 let mut guard = self.f16_scratch.lock().unwrap();
429 if guard.is_none() {
430 *guard = Some(F16Scratch {
431 xh: self.alloc_u8_uninit(2)?,
432 ws: self.alloc_u8_uninit(F16_WS_BYTES)?,
433 cap_xh: 2,
434 });
435 }
436 let s = guard.as_mut().unwrap();
437 let rc = {
438 let stream = self.gpu.stream();
439 let (w_p, _gw) = w16.device_ptr(&stream);
440 let (h_p, _gh) = xh.device_ptr(&stream);
441 let (y_p, _gy) = y.device_ptr_mut(&stream);
442 let (ws_p, _gws) = s.ws.device_ptr_mut(&stream);
443 unsafe {
444 memra_f16_pp_gemm_pre(
445 w_p as *const core::ffi::c_void,
446 h_p as *const core::ffi::c_void,
447 (y_p as *mut f32).add(off_elems),
448 m as i32,
449 out_f as i32,
450 in_f as i32,
451 ws_p as *mut core::ffi::c_void,
452 F16_WS_BYTES,
453 stream.cu_stream() as *mut core::ffi::c_void,
454 )
455 }
456 };
457 if rc != 0 {
458 return Err(format!(
459 "memra_f16_pp_gemm_pre(into_off) rc={rc} (m={m} n={out_f} k={in_f})"
460 )
461 .into());
462 }
463 Ok(true)
464 }
465
466 pub fn try_f16_gemm_pre(
469 &self,
470 w: &crate::model::GpuTensor,
471 xh: &CudaSlice<u8>,
472 m: usize,
473 ) -> Result<Option<CudaSlice<f32>>, Box<dyn std::error::Error>> {
474 use crate::model::GpuTensor;
475 let (w16, ne, scale) = match w {
476 GpuTensor::Quant {
477 f16: Some(w16),
478 ne,
479 scale,
480 ..
481 } => (w16, ne, *scale),
482 _ => return Ok(None),
483 };
484 let (in_f, out_f) = (ne[0] as usize, ne[1] as usize);
485 let mut guard = self.f16_scratch.lock().unwrap();
487 if guard.is_none() {
488 *guard = Some(F16Scratch {
489 xh: self.alloc_u8_uninit(2)?,
490 ws: self.alloc_u8_uninit(F16_WS_BYTES)?,
491 cap_xh: 2,
492 });
493 }
494 let s = guard.as_mut().unwrap();
495 let mut y = self.uninit(m * out_f)?;
496 let rc = {
497 let stream = self.gpu.stream();
498 let (w_p, _gw) = w16.device_ptr(&stream);
499 let (h_p, _gh) = xh.device_ptr(&stream);
500 let (y_p, _gy) = y.device_ptr_mut(&stream);
501 let (ws_p, _gws) = s.ws.device_ptr_mut(&stream);
502 unsafe {
503 memra_f16_pp_gemm_pre(
504 w_p as *const core::ffi::c_void,
505 h_p as *const core::ffi::c_void,
506 y_p as *mut f32,
507 m as i32,
508 out_f as i32,
509 in_f as i32,
510 ws_p as *mut core::ffi::c_void,
511 F16_WS_BYTES,
512 stream.cu_stream() as *mut core::ffi::c_void,
513 )
514 }
515 };
516 if rc != 0 {
517 return Err(format!("memra_f16_pp_gemm_pre rc={rc} (m={m} n={out_f} k={in_f})").into());
518 }
519 if scale != 1.0 {
520 self.scale_inplace(&mut y, scale, m * out_f)?;
521 }
522 Ok(Some(y))
523 }
524
525 pub fn build_q8_f16_raw(
528 &self,
529 bytes: &CudaSlice<u8>,
530 in_f: usize,
531 out_f: usize,
532 ) -> Result<CudaSlice<u8>, Box<dyn std::error::Error>> {
533 assert!(in_f % 32 == 0);
534 let nblk = in_f / 32;
535 let mut dst = self.alloc_u8_uninit(out_f * in_f * 2)?;
536 let rc = {
537 let stream = self.gpu.stream();
538 let (s_p, _gs) = bytes.device_ptr(&stream);
539 let (d_p, _gd) = dst.device_ptr_mut(&stream);
540 unsafe {
541 memra_q8_0_dequant_f16(
542 s_p as *const core::ffi::c_void,
543 d_p as *mut core::ffi::c_void,
544 out_f as i64,
545 nblk as i64,
546 stream.cu_stream() as *mut core::ffi::c_void,
547 )
548 }
549 };
550 if rc != 0 {
551 return Err(format!("memra_q8_0_dequant_f16 rc={rc}").into());
552 }
553 Ok(dst)
554 }
555
556 pub fn build_q8_f16(
559 &self,
560 t: &mut crate::model::GpuTensor,
561 ) -> Result<(), Box<dyn std::error::Error>> {
562 use crate::model::GpuTensor;
563 let GpuTensor::Quant {
564 bytes,
565 qtype,
566 row_bytes,
567 ne,
568 f16,
569 ..
570 } = t
571 else {
572 return Ok(());
573 };
574 let q4 = *qtype == crate::QT_Q4_0;
582 let q6k = *qtype == crate::QT_Q6_K;
583 let q4k = *qtype == crate::QT_Q4_K;
584 let q5k = *qtype == crate::QT_Q5_K;
585 if (*qtype != crate::QT_Q8_0 && !q4 && !q6k && !q4k && !q5k)
586 || f16.is_some()
587 || ne.len() != 2
588 {
589 return Ok(());
590 }
591 let (in_f, out_f) = (ne[0] as usize, ne[1] as usize);
592 if q6k || q4k || q5k {
593 let sb = if q6k {
594 210
595 } else if q5k {
596 176
597 } else {
598 144
599 };
600 if in_f % 256 != 0 || *row_bytes != (in_f / 256) * sb {
601 return Ok(());
602 }
603 } else if in_f % 32 != 0 || *row_bytes != (in_f / 32) * (if q4 { 18 } else { 34 }) {
604 return Ok(());
605 }
606 use std::sync::atomic::{AtomicUsize, Ordering};
609 static SPENT: AtomicUsize = AtomicUsize::new(0);
610 static BUDGET: std::sync::OnceLock<usize> = std::sync::OnceLock::new();
611 let budget = *BUDGET.get_or_init(|| {
612 std::env::var("MEMRA_PP_F16_BUDGET_MB")
613 .ok()
614 .and_then(|v| v.parse::<usize>().ok())
615 .unwrap_or(32768)
616 << 20
617 });
618 let sz = out_f * in_f * 2;
619 if SPENT.fetch_add(sz, Ordering::Relaxed) + sz > budget {
620 SPENT.fetch_sub(sz, Ordering::Relaxed);
621 return Ok(());
622 }
623 let mut mirror = if q6k {
624 self.build_q6k_f16_raw(bytes, in_f, out_f)?
625 } else if q4k {
626 self.build_q4k_f16_raw(bytes, in_f, out_f)?
627 } else if q5k {
628 self.build_q5k_f16_raw(bytes, in_f, out_f)?
629 } else if q4 {
630 self.build_q4_f16_raw(bytes, in_f, out_f)?
631 } else {
632 self.build_q8_f16_raw(bytes, in_f, out_f)?
633 };
634 static SIM: std::sync::OnceLock<bool> = std::sync::OnceLock::new();
643 if *SIM.get_or_init(|| {
644 matches!(
645 std::env::var("MEMRA_W8A8_SIM").as_deref(),
646 Ok("1") | Ok("2")
647 )
648 }) {
649 fn f16_bits_to_f32(b: u16) -> f32 {
650 let (s, e, m) = (
651 (b >> 15) as u32,
652 ((b >> 10) & 0x1f) as u32,
653 (b & 0x3ff) as u32,
654 );
655 let bits = if e == 0 {
656 if m == 0 {
657 s << 31
658 } else {
659 let mut e2 = 127 - 15 + 1;
661 let mut m2 = m;
662 while m2 & 0x400 == 0 {
663 m2 <<= 1;
664 e2 -= 1;
665 }
666 (s << 31) | ((e2 as u32) << 23) | ((m2 & 0x3ff) << 13)
667 }
668 } else if e == 0x1f {
669 (s << 31) | (0xff << 23) | (m << 13)
670 } else {
671 (s << 31) | ((e + 127 - 15) << 23) | (m << 13)
672 };
673 f32::from_bits(bits)
674 }
675 fn f32_to_f16_bits(v: f32) -> u16 {
676 let b = v.to_bits();
677 let (s, e, m) = ((b >> 31) as u16, ((b >> 23) & 0xff) as i32, b & 0x7fffff);
678 if e == 0xff {
679 return (s << 15) | 0x7c00 | ((m >> 13) as u16 & 0x3ff);
680 }
681 let e2 = e - 127 + 15;
682 if e2 >= 0x1f {
683 return (s << 15) | 0x7c00;
684 }
685 if e2 <= 0 {
686 if e2 < -10 {
687 return s << 15;
688 }
689 let m2 = (m | 0x800000) >> (1 - e2);
690 let r = (m2 >> 13) as u16 + ((m2 >> 12) & 1) as u16;
692 return (s << 15) | r;
693 }
694 let mut r = ((e2 as u32) << 10) as u16 | (m >> 13) as u16;
695 if m & 0x1000 != 0 {
696 r += 1;
697 }
698 (s << 15) | r
699 }
700 let host: Vec<u8> = self.dtoh_u8(&mirror)?;
701 let mut vals: Vec<f32> = host
702 .chunks_exact(2)
703 .map(|c| f16_bits_to_f32(u16::from_le_bytes([c[0], c[1]])))
704 .collect();
705 for row in vals.chunks_mut(in_f) {
706 let amax = row.iter().fold(0f32, |a, &v| a.max(v.abs()));
707 if amax > 0.0 {
708 let d = amax / 127.0;
709 for v in row.iter_mut() {
710 *v = (*v / d).round().clamp(-127.0, 127.0) * d;
711 }
712 }
713 }
714 let out: Vec<u8> = vals
715 .iter()
716 .flat_map(|&v| f32_to_f16_bits(v).to_le_bytes())
717 .collect();
718 mirror = self.htod_bytes(&out)?;
719 }
720 *f16 = Some(mirror);
721 Ok(())
722 }
723
724 pub fn build_q4_f16_raw(
726 &self,
727 bytes: &CudaSlice<u8>,
728 in_f: usize,
729 out_f: usize,
730 ) -> Result<CudaSlice<u8>, Box<dyn std::error::Error>> {
731 assert!(in_f % 32 == 0);
732 let nblk = in_f / 32;
733 let mut dst = self.alloc_u8_uninit(out_f * in_f * 2)?;
734 let rc = {
735 let stream = self.gpu.stream();
736 let (s_p, _gs) = bytes.device_ptr(&stream);
737 let (d_p, _gd) = dst.device_ptr_mut(&stream);
738 unsafe {
739 memra_q4_0_dequant_f16(
740 s_p as *const core::ffi::c_void,
741 d_p as *mut core::ffi::c_void,
742 out_f as i64,
743 nblk as i64,
744 stream.cu_stream() as *mut core::ffi::c_void,
745 )
746 }
747 };
748 if rc != 0 {
749 return Err(format!("memra_q4_0_dequant_f16 rc={rc}").into());
750 }
751 Ok(dst)
752 }
753
754 pub fn build_q5k_f16_raw(
757 &self,
758 bytes: &CudaSlice<u8>,
759 in_f: usize,
760 out_f: usize,
761 ) -> Result<CudaSlice<u8>, Box<dyn std::error::Error>> {
762 assert!(in_f % 256 == 0);
763 let nsb = in_f / 256;
764 let mut dst = self.alloc_u8_uninit(out_f * in_f * 2)?;
765 let rc = {
766 let stream = self.gpu.stream();
767 let (s_p, _gs) = bytes.device_ptr(&stream);
768 let (d_p, _gd) = dst.device_ptr_mut(&stream);
769 unsafe {
770 memra_q5_K_dequant_f16(
771 s_p as *const core::ffi::c_void,
772 d_p as *mut core::ffi::c_void,
773 out_f as i64,
774 nsb as i64,
775 stream.cu_stream() as *mut core::ffi::c_void,
776 )
777 }
778 };
779 if rc != 0 {
780 return Err(format!("memra_q5_K_dequant_f16 rc={rc}").into());
781 }
782 Ok(dst)
783 }
784
785 pub fn build_q4k_f16_raw(
788 &self,
789 bytes: &CudaSlice<u8>,
790 in_f: usize,
791 out_f: usize,
792 ) -> Result<CudaSlice<u8>, Box<dyn std::error::Error>> {
793 assert!(in_f % 256 == 0);
794 let nsb = in_f / 256;
795 let mut dst = self.alloc_u8_uninit(out_f * in_f * 2)?;
796 let rc = {
797 let stream = self.gpu.stream();
798 let (s_p, _gs) = bytes.device_ptr(&stream);
799 let (d_p, _gd) = dst.device_ptr_mut(&stream);
800 unsafe {
801 memra_q4_K_dequant_f16(
802 s_p as *const core::ffi::c_void,
803 d_p as *mut core::ffi::c_void,
804 out_f as i64,
805 nsb as i64,
806 stream.cu_stream() as *mut core::ffi::c_void,
807 )
808 }
809 };
810 if rc != 0 {
811 return Err(format!("memra_q4_K_dequant_f16 rc={rc}").into());
812 }
813 Ok(dst)
814 }
815
816 pub fn build_q6k_f16_raw(
817 &self,
818 bytes: &CudaSlice<u8>,
819 in_f: usize,
820 out_f: usize,
821 ) -> Result<CudaSlice<u8>, Box<dyn std::error::Error>> {
822 assert!(in_f % 256 == 0);
823 let nsb = in_f / 256;
824 let mut dst = self.alloc_u8_uninit(out_f * in_f * 2)?;
825 let rc = {
826 let stream = self.gpu.stream();
827 let (s_p, _gs) = bytes.device_ptr(&stream);
828 let (d_p, _gd) = dst.device_ptr_mut(&stream);
829 unsafe {
830 memra_q6_K_dequant_f16(
831 s_p as *const core::ffi::c_void,
832 d_p as *mut core::ffi::c_void,
833 out_f as i64,
834 nsb as i64,
835 stream.cu_stream() as *mut core::ffi::c_void,
836 )
837 }
838 };
839 if rc != 0 {
840 return Err(format!("memra_q6_K_dequant_f16 rc={rc}").into());
841 }
842 Ok(dst)
843 }
844}