use candle_core::DType;
use crate::registry::Backend;
use crate::registry::BackendSupport;
use crate::registry::CellException;
use crate::registry::DtypeBackendSupport;
use crate::registry::DtypeSupport;
use crate::registry::Support;
const RUN_STATES: [Support; 3] = [Support::Untested, Support::Unsupported, Support::Pending];
const DTYPES: [DType; 3] = [DType::F32, DType::F16, DType::BF16];
const BACKENDS: [Backend; 3] = [Backend::Cpu, Backend::Metal, Backend::Cuda];
fn cuda_may_take(status: Support, reason: &str) -> bool {
status == Support::Untested || (status == Support::Unsupported && cites_a_run(reason))
}
fn cites_a_run(reason: &str) -> bool {
reason
.split("run ")
.skip(1)
.any(|rest| rest.starts_with(|c: char| c.is_ascii_digit()))
}
pub(crate) struct Cells<'a> {
pub id: &'a str,
pub backends: BackendSupport,
pub dtypes: DtypeSupport,
pub accel_only: &'a [DType],
pub exceptions: &'a [CellException],
pub rows: DtypeBackendSupport,
}
impl Cells<'_> {
fn derived(&self, accel_only: &[DType]) -> DtypeBackendSupport {
DtypeBackendSupport::derive(self.backends, self.dtypes, accel_only)
}
pub(crate) fn exception_violation(&self) -> Option<String> {
let id = self.id;
let derived = self.derived(self.accel_only);
let mut seen = Vec::new();
for exception in self.exceptions {
let (dtype, backend, status) = (exception.dtype, exception.backend, exception.status);
let mut accel_only = self.accel_only.to_vec();
accel_only.push(dtype);
let broken = if !DTYPES.contains(&dtype) {
"names no catalog dtype"
} else if exception.reason.trim().is_empty() {
"gives no reason"
} else if !RUN_STATES.contains(&status) {
"writes a status no run leaves"
} else if backend == Backend::Cuda && !cuda_may_take(status, exception.reason) {
"writes a CUDA cell other than untested or a failure a cited run measured"
} else if seen.contains(&(dtype, backend)) {
"shares its cell with another exception"
} else if derived.row(dtype).get(backend) == status {
"restates what the derivation already gives"
} else if derived.with_exceptions(&[*exception]) == self.derived(&accel_only) {
"is a processor refusal, which accel_only_dtypes states"
} else if self.rows.row(dtype).get(backend) != status {
"does not reach the descriptor"
} else {
seen.push((dtype, backend));
continue;
};
return Some(format!("{id}: {exception:?} {broken}"));
}
None
}
pub(crate) fn verified_by_an_exception(&self) -> Vec<(DType, Backend)> {
let derived = self.derived(self.accel_only);
DTYPES
.into_iter()
.flat_map(|dtype| BACKENDS.map(|backend| (dtype, backend)))
.filter(|&(dtype, backend)| {
self.rows.row(dtype).get(backend) == Support::Verified
&& derived.row(dtype).get(backend) != Support::Verified
})
.collect()
}
}