use ironaccelerator_core::{
Backend, BackendKind, Capability, CapabilityFlags, ComputeTier, DeviceDescriptor, DeviceId,
Result, Vendor,
};
use crate::drv::{EnumeratedDevice, ZE_DEVICE_TYPE_GPU, ZE_DEVICE_TYPE_VPU};
pub struct LevelZeroBackend;
pub static LEVELZERO_BACKEND: LevelZeroBackend = LevelZeroBackend;
impl Backend for LevelZeroBackend {
fn kind(&self) -> BackendKind {
BackendKind::LevelZero
}
fn is_available(&self) -> bool {
crate::drv::is_available() && !crate::drv::enumerate().is_empty()
}
fn enumerate(&self) -> Result<Vec<DeviceDescriptor>> {
Ok(crate::drv::enumerate().into_iter().map(describe).collect())
}
fn capabilities(&self, device: u32) -> Result<CapabilityFlags> {
crate::drv::enumerate()
.into_iter()
.find(|d| d.ordinal == device)
.map(|d| flags_for(&d))
.ok_or(ironaccelerator_core::Error::InvalidArgument(
"level-zero device ordinal out of range",
))
}
}
fn flags_for(d: &EnumeratedDevice) -> CapabilityFlags {
let mut flags = CapabilityFlags::FP32
| CapabilityFlags::FP16
| CapabilityFlags::BF16
| CapabilityFlags::INT8
| CapabilityFlags::MULTI_STREAM;
if d.type_ == ZE_DEVICE_TYPE_GPU {
flags |= CapabilityFlags::WMMA | CapabilityFlags::INT4;
}
flags
}
fn describe(d: EnumeratedDevice) -> DeviceDescriptor {
let vendor = match d.vendor_id {
0x8086 => Vendor::Intel,
0x10DE => Vendor::Nvidia,
0x1002 => Vendor::Amd,
_ => Vendor::Other,
};
let flags = flags_for(&d);
let (tier, arch_prefix) = match d.type_ {
ZE_DEVICE_TYPE_GPU => (ComputeTier::Consumer, "xe"),
ZE_DEVICE_TYPE_VPU => (ComputeTier::Mobile, "vpu"),
_ => (ComputeTier::Baseline, "ze"),
};
DeviceDescriptor {
id: DeviceId {
backend: BackendKind::LevelZero,
ordinal: d.ordinal,
},
vendor,
name: d.name,
arch: format!("{arch_prefix}-{:04x}", d.device_id),
total_memory_bytes: d.max_mem_alloc_size,
multiprocessor_count: d
.num_slices
.saturating_mul(d.num_subslices_per_slice)
.saturating_mul(d.num_eus_per_subslice),
clock_khz: d.core_clock_khz,
capability: Capability {
flags,
tier,
fp16_tflops: None,
fp8_tflops: None,
mem_bandwidth_gbs: None,
},
}
}