use crate::quant::{Q4Matrix, QMatrix};
use std::any::Any;
use std::sync::OnceLock;
pub enum WeightRef<'a> {
Bf16(&'a [u16]),
Q8(&'a QMatrix),
Q4(&'a Q4Matrix),
}
impl WeightRef<'_> {
pub fn bytes(&self) -> usize {
match self {
WeightRef::Bf16(w) => w.len() * 2,
WeightRef::Q8(m) => m.bytes(),
WeightRef::Q4(m) => m.bytes(),
}
}
}
pub type DeviceWeight = Box<dyn Any + Send + Sync>;
pub struct Job<'a> {
pub w: WeightRef<'a>,
pub dev: &'a DeviceWeight,
pub n_out: usize,
pub y: &'a mut [f32],
}
pub trait Backend: Send + Sync {
fn name(&self) -> &str;
fn wants(&self, n_out: usize, n_in: usize, t: usize) -> bool;
fn upload(&self, w: &WeightRef, n_out: usize, n_in: usize) -> Option<DeviceWeight>;
fn matmul(&self, x: &[f32], t: usize, n_in: usize, jobs: &mut [Job]) -> bool;
fn stats(&self) -> Option<String> {
None
}
}
static ACTIVE: OnceLock<Option<Box<dyn Backend>>> = OnceLock::new();
pub fn install(b: Option<Box<dyn Backend>>) {
let _ = ACTIVE.set(b);
}
pub fn active() -> Option<&'static dyn Backend> {
ACTIVE.get().and_then(|b| b.as_deref())
}
pub fn init(plat: &crate::platform::Platform, pref: crate::platform::DevicePref) -> Option<&'static dyn Backend> {
use crate::platform::DevicePref;
let chosen: Option<Box<dyn Backend>> = match plat.pick(pref) {
None => None,
Some(g) => {
let r: Result<Box<dyn Backend>, String> = match g.kind {
#[cfg(all(feature = "gpu", any(target_os = "macos", target_os = "ios"), target_arch = "aarch64"))]
crate::platform::GpuKind::Metal => crate::metal::MetalBackend::new()
.map(|b| Box::new(b) as Box<dyn Backend>)
.map_err(|e| e.to_string()),
#[cfg(all(feature = "gpu", not(any(target_os = "macos", target_os = "ios", target_arch = "wasm32"))))]
crate::platform::GpuKind::Cuda => crate::cuda::CudaBackend::new(g.index)
.map(|b| Box::new(b) as Box<dyn Backend>)
.map_err(|e| e.to_string()),
_ => Err(format!("{} compute is not implemented in this build", g.kind.as_str())),
};
match r {
Ok(b) => Some(b),
Err(e) => {
if pref != DevicePref::Auto || !e.contains("not implemented") {
eprintln!("[{}: {e}; using CPU]", g.kind.as_str());
}
None
}
}
}
};
install(chosen);
active()
}