#![allow(unused_variables)]
use super::traits::{
AsyncOperationHandle, DeviceMemory, DeviceStatus, HardwareBackend, HardwareDevice, MemoryType,
};
use super::{
DataType, HardwareCapabilities, HardwareConfig, HardwareMetrics, HardwareResult, HardwareType,
};
use crate::errors::TrustformersError;
use async_trait::async_trait;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::time::{Duration, SystemTime};
use tokio::time;
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum AsicType {
AIInference,
NPU,
TPU,
DSP,
VPU,
Crypto,
EdgeAI,
Custom(String),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AsicVendor {
pub name: String,
pub id: u16,
pub driver_version: String,
pub firmware_version: String,
pub support_contact: Option<String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AsicSpec {
pub asic_type: AsicType,
pub vendor: AsicVendor,
pub model: String,
pub revision: String,
pub process_node: Option<u16>,
pub die_size: Option<f64>,
pub package: Option<String>,
pub frequency_range: Option<(u32, u32)>,
pub power_range: Option<(f64, f64)>,
pub temperature_range: Option<(f64, f64)>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AsicDeviceConfig {
pub base_config: HardwareConfig,
pub spec: AsicSpec,
pub clock_frequency: Option<u32>,
pub voltage: Option<f64>,
pub power_limit: Option<f64>,
pub thermal_limit: Option<f64>,
pub memory_config: AsicMemoryConfig,
pub instruction_set: Option<String>,
pub init_params: HashMap<String, String>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AsicMemoryConfig {
pub on_chip_memory: Option<usize>,
pub off_chip_memory: Option<usize>,
pub memory_bandwidth: Option<f64>,
pub memory_latency: Option<f64>,
pub cache_config: CacheConfig,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct CacheConfig {
pub l1_size: Option<usize>,
pub l2_size: Option<usize>,
pub l3_size: Option<usize>,
pub line_size: Option<usize>,
pub associativity: Option<u8>,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AsicOperationSet {
pub name: String,
pub operations: Vec<String>,
pub performance: HashMap<String, f64>,
pub memory_requirements: HashMap<String, usize>,
pub precision_support: Vec<DataType>,
pub instruction_encoding: Option<String>,
}
pub struct AsicDevice {
config: AsicDeviceConfig,
status: Arc<Mutex<DeviceStatus>>,
capabilities: HardwareCapabilities,
operation_sets: Vec<AsicOperationSet>,
memory_pools: Arc<Mutex<HashMap<String, Vec<DeviceMemory>>>>,
active_operations: Arc<Mutex<HashMap<String, AsyncOperationHandle>>>,
driver: Option<Box<dyn AsicDriver>>,
performance_monitor: Arc<Mutex<AsicPerformanceMonitor>>,
}
#[async_trait]
pub trait AsicDriver: Send + Sync {
async fn initialize(&mut self, config: &AsicDeviceConfig) -> HardwareResult<()>;
async fn execute_instruction(&self, instruction: &[u8]) -> HardwareResult<Vec<u8>>;
async fn read_register(&self, address: u64) -> HardwareResult<u64>;
async fn write_register(&self, address: u64, value: u64) -> HardwareResult<()>;
async fn transfer_to_device(&self, data: &[u8], address: u64) -> HardwareResult<()>;
async fn transfer_from_device(&self, address: u64, size: usize) -> HardwareResult<Vec<u8>>;
async fn get_status(&self) -> HardwareResult<DeviceStatus>;
async fn reset(&mut self) -> HardwareResult<()>;
async fn configure(&mut self, config: &AsicDeviceConfig) -> HardwareResult<()>;
async fn get_metrics(&self) -> HardwareResult<HardwareMetrics>;
}
#[derive(Debug, Clone)]
pub struct AsicPerformanceMonitor {
pub operation_counters: HashMap<String, u64>,
pub metrics: HardwareMetrics,
pub thermal_history: Vec<(SystemTime, f64)>,
pub power_history: Vec<(SystemTime, f64)>,
pub error_counters: HashMap<String, u64>,
pub utilization_history: Vec<(SystemTime, f64)>,
}
impl AsicDevice {
pub fn new(config: AsicDeviceConfig) -> Self {
let capabilities = Self::build_capabilities(&config);
let operation_sets = Self::build_operation_sets(&config);
Self {
config,
status: Arc::new(Mutex::new(DeviceStatus::default())),
capabilities,
operation_sets,
memory_pools: Arc::new(Mutex::new(HashMap::new())),
active_operations: Arc::new(Mutex::new(HashMap::new())),
driver: None,
performance_monitor: Arc::new(Mutex::new(AsicPerformanceMonitor::new())),
}
}
pub fn set_driver(&mut self, driver: Box<dyn AsicDriver>) {
self.driver = Some(driver);
}
fn build_capabilities(config: &AsicDeviceConfig) -> HardwareCapabilities {
let mut capabilities = HardwareCapabilities::default();
match config.spec.asic_type {
AsicType::AIInference | AsicType::NPU => {
capabilities.data_types = vec![
DataType::F32,
DataType::F16,
DataType::BF16,
DataType::I8,
DataType::I16,
DataType::I32,
];
},
AsicType::TPU => {
capabilities.data_types = vec![DataType::F32, DataType::BF16, DataType::I8];
},
AsicType::DSP => {
capabilities.data_types = vec![
DataType::F32,
DataType::F64,
DataType::I16,
DataType::I32,
DataType::Complex64,
DataType::Complex128,
];
},
AsicType::VPU => {
capabilities.data_types = vec![DataType::F16, DataType::I8, DataType::U8];
},
AsicType::Crypto => {
capabilities.data_types =
vec![DataType::U8, DataType::U16, DataType::U32, DataType::U64];
},
AsicType::EdgeAI => {
capabilities.data_types = vec![DataType::F16, DataType::I8, DataType::U8];
},
AsicType::Custom(_) => {
capabilities.data_types = vec![DataType::F32, DataType::I32];
},
}
if let Some(on_chip) = config.memory_config.on_chip_memory {
capabilities.memory_size = Some(on_chip);
} else if let Some(off_chip) = config.memory_config.off_chip_memory {
capabilities.memory_size = Some(off_chip);
}
if let Some(freq) = config.clock_frequency {
capabilities.clock_frequency = Some(freq as u64 * 1_000_000); }
capabilities.operations = match config.spec.asic_type {
AsicType::AIInference | AsicType::NPU => vec![
"matmul".to_string(),
"conv2d".to_string(),
"activation".to_string(),
"pooling".to_string(),
"normalization".to_string(),
"attention".to_string(),
],
AsicType::TPU => vec![
"matmul".to_string(),
"conv2d".to_string(),
"systolic_array".to_string(),
],
AsicType::DSP => vec![
"fft".to_string(),
"filter".to_string(),
"transform".to_string(),
"correlation".to_string(),
],
AsicType::VPU => vec![
"conv2d".to_string(),
"pooling".to_string(),
"resize".to_string(),
"color_space".to_string(),
],
AsicType::Crypto => vec![
"encrypt".to_string(),
"decrypt".to_string(),
"hash".to_string(),
"signature".to_string(),
],
AsicType::EdgeAI => vec![
"inference".to_string(),
"quantization".to_string(),
"compression".to_string(),
],
AsicType::Custom(_) => vec!["custom_op".to_string()],
};
capabilities
}
fn build_operation_sets(config: &AsicDeviceConfig) -> Vec<AsicOperationSet> {
let mut operation_sets = Vec::new();
match config.spec.asic_type {
AsicType::AIInference | AsicType::NPU => {
operation_sets.push(AsicOperationSet {
name: "ml_ops".to_string(),
operations: vec![
"matmul".to_string(),
"conv2d".to_string(),
"activation".to_string(),
"pooling".to_string(),
"normalization".to_string(),
"attention".to_string(),
],
performance: [
("matmul".to_string(), 1000.0),
("conv2d".to_string(), 800.0),
("activation".to_string(), 2000.0),
]
.into(),
memory_requirements: [
("matmul".to_string(), 1024 * 1024),
("conv2d".to_string(), 2048 * 1024),
]
.into(),
precision_support: vec![DataType::F32, DataType::F16, DataType::I8],
instruction_encoding: Some("custom_ml".to_string()),
});
},
AsicType::TPU => {
operation_sets.push(AsicOperationSet {
name: "tensor_ops".to_string(),
operations: vec![
"matmul".to_string(),
"conv2d".to_string(),
"systolic_array".to_string(),
],
performance: [
("matmul".to_string(), 2000.0),
("systolic_array".to_string(), 3000.0),
]
.into(),
memory_requirements: [
("matmul".to_string(), 512 * 1024),
("systolic_array".to_string(), 1024 * 1024),
]
.into(),
precision_support: vec![DataType::F32, DataType::BF16, DataType::I8],
instruction_encoding: Some("tpu_v4".to_string()),
});
},
AsicType::DSP => {
operation_sets.push(AsicOperationSet {
name: "signal_ops".to_string(),
operations: vec![
"fft".to_string(),
"filter".to_string(),
"transform".to_string(),
"correlation".to_string(),
],
performance: [("fft".to_string(), 1500.0), ("filter".to_string(), 1200.0)]
.into(),
memory_requirements: [
("fft".to_string(), 256 * 1024),
("filter".to_string(), 128 * 1024),
]
.into(),
precision_support: vec![DataType::F32, DataType::F64, DataType::Complex64],
instruction_encoding: Some("dsp_v2".to_string()),
});
},
_ => {
operation_sets.push(AsicOperationSet {
name: "basic_ops".to_string(),
operations: vec!["generic_op".to_string()],
performance: [("generic_op".to_string(), 100.0)].into(),
memory_requirements: [("generic_op".to_string(), 64 * 1024)].into(),
precision_support: vec![DataType::F32],
instruction_encoding: None,
});
},
}
operation_sets
}
pub fn get_operation_set(&self, name: &str) -> Option<&AsicOperationSet> {
self.operation_sets.iter().find(|ops| ops.name == name)
}
#[allow(dead_code)]
async fn update_performance_metrics(&self) -> HardwareResult<()> {
if let Some(driver) = &self.driver {
let metrics = driver.get_metrics().await?;
let mut monitor = self.performance_monitor.lock().expect("Lock poisoned");
monitor
.thermal_history
.push((SystemTime::now(), metrics.temperature.unwrap_or(0.0)));
monitor.power_history.push((SystemTime::now(), metrics.power_consumption));
monitor.utilization_history.push((SystemTime::now(), metrics.utilization));
monitor.metrics = metrics;
if monitor.thermal_history.len() > 1000 {
monitor.thermal_history.drain(..500);
}
if monitor.power_history.len() > 1000 {
monitor.power_history.drain(..500);
}
if monitor.utilization_history.len() > 1000 {
monitor.utilization_history.drain(..500);
}
}
Ok(())
}
pub fn get_performance_statistics(&self) -> HashMap<String, f64> {
let monitor = self.performance_monitor.lock().expect("Lock poisoned");
let mut stats = HashMap::new();
if !monitor.utilization_history.is_empty() {
let avg_util = monitor.utilization_history.iter().map(|(_, util)| util).sum::<f64>()
/ monitor.utilization_history.len() as f64;
stats.insert("avg_utilization".to_string(), avg_util);
}
if !monitor.thermal_history.is_empty() {
let avg_temp = monitor.thermal_history.iter().map(|(_, temp)| temp).sum::<f64>()
/ monitor.thermal_history.len() as f64;
stats.insert("avg_temperature".to_string(), avg_temp);
}
if !monitor.power_history.is_empty() {
let avg_power = monitor.power_history.iter().map(|(_, power)| power).sum::<f64>()
/ monitor.power_history.len() as f64;
stats.insert("avg_power".to_string(), avg_power);
}
for (op, count) in &monitor.operation_counters {
stats.insert(format!("op_{}", op), *count as f64);
}
stats
}
}
#[async_trait]
impl HardwareDevice for AsicDevice {
fn device_id(&self) -> &str {
&self.config.base_config.device_id
}
fn hardware_type(&self) -> HardwareType {
HardwareType::ASIC
}
fn capabilities(&self) -> &HardwareCapabilities {
&self.capabilities
}
async fn initialize(&mut self, config: &HardwareConfig) -> HardwareResult<()> {
self.config.base_config = config.clone();
if let Some(driver) = &mut self.driver {
driver.initialize(&self.config).await?;
}
let mut status = self.status.lock().expect("Lock poisoned");
status.online = true;
status.busy = false;
status.error = None;
Ok(())
}
async fn shutdown(&mut self) -> HardwareResult<()> {
let operations = {
let mut ops = self.active_operations.lock().expect("Lock poisoned");
let handles: Vec<_> = ops.keys().cloned().collect();
ops.clear();
handles
};
{
let mut status = self.status.lock().expect("Lock poisoned");
status.online = false;
status.busy = false;
}
if let Some(driver) = &mut self.driver {
driver.reset().await?;
}
Ok(())
}
fn is_available(&self) -> bool {
let status = self.status.lock().expect("Lock poisoned");
status.online && !status.busy
}
fn status(&self) -> DeviceStatus {
self.status.lock().expect("Lock poisoned").clone()
}
async fn metrics(&self) -> HardwareResult<HardwareMetrics> {
if let Some(driver) = &self.driver {
driver.get_metrics().await
} else {
Ok(HardwareMetrics {
ops_per_second: 0.0,
memory_bandwidth: 0.0,
utilization: 0.0,
power_consumption: 0.0,
temperature: None,
error_rate: 0.0,
latency: 0.0,
throughput: 0.0,
})
}
}
async fn reset(&mut self) -> HardwareResult<()> {
if let Some(driver) = &mut self.driver {
driver.reset().await?;
}
self.memory_pools.lock().expect("Lock poisoned").clear();
self.active_operations.lock().expect("Lock poisoned").clear();
let mut monitor = self.performance_monitor.lock().expect("Lock poisoned");
monitor.operation_counters.clear();
monitor.thermal_history.clear();
monitor.power_history.clear();
monitor.error_counters.clear();
monitor.utilization_history.clear();
Ok(())
}
async fn allocate_memory(&mut self, size: usize) -> HardwareResult<DeviceMemory> {
let address = (size.wrapping_mul(12345)) % 0x100000000; let memory = DeviceMemory {
address,
size,
memory_type: MemoryType::Local,
device_id: self.device_id().to_string(),
};
let mut pools = self.memory_pools.lock().expect("Lock poisoned");
pools.entry("default".to_string()).or_default().push(memory.clone());
Ok(memory)
}
async fn free_memory(&mut self, memory: DeviceMemory) -> HardwareResult<()> {
let mut pools = self.memory_pools.lock().expect("Lock poisoned");
if let Some(pool) = pools.get_mut("default") {
pool.retain(|m| m.address != memory.address);
}
Ok(())
}
async fn synchronize(&self) -> HardwareResult<()> {
let has_operations = {
let operations = self.active_operations.lock().expect("Lock poisoned");
!operations.is_empty()
};
if has_operations {
time::sleep(Duration::from_millis(1)).await;
}
Ok(())
}
}
impl Default for AsicPerformanceMonitor {
fn default() -> Self {
Self::new()
}
}
impl AsicPerformanceMonitor {
pub fn new() -> Self {
Self {
operation_counters: HashMap::new(),
metrics: HardwareMetrics {
ops_per_second: 0.0,
memory_bandwidth: 0.0,
utilization: 0.0,
power_consumption: 0.0,
temperature: None,
error_rate: 0.0,
latency: 0.0,
throughput: 0.0,
},
thermal_history: Vec::new(),
power_history: Vec::new(),
error_counters: HashMap::new(),
utilization_history: Vec::new(),
}
}
pub fn record_operation(&mut self, operation: &str) {
*self.operation_counters.entry(operation.to_string()).or_insert(0) += 1;
}
pub fn record_error(&mut self, error_type: &str) {
*self.error_counters.entry(error_type.to_string()).or_insert(0) += 1;
}
pub fn get_operation_stats(&self) -> HashMap<String, u64> {
self.operation_counters.clone()
}
pub fn get_error_stats(&self) -> HashMap<String, u64> {
self.error_counters.clone()
}
}
pub struct AsicBackend {
name: String,
version: String,
#[allow(dead_code)]
supported_types: Vec<AsicType>,
device_configs: HashMap<String, AsicDeviceConfig>,
driver_factory: Option<Box<dyn AsicDriverFactory>>,
}
pub trait AsicDriverFactory: Send + Sync {
fn create_driver(&self, asic_type: &AsicType) -> HardwareResult<Box<dyn AsicDriver>>;
fn is_available(&self, asic_type: &AsicType) -> bool;
fn get_requirements(&self, asic_type: &AsicType) -> Vec<String>;
}
impl AsicBackend {
pub fn new(name: String, version: String) -> Self {
Self {
name,
version,
supported_types: vec![
AsicType::AIInference,
AsicType::NPU,
AsicType::TPU,
AsicType::DSP,
AsicType::VPU,
AsicType::Crypto,
AsicType::EdgeAI,
],
device_configs: HashMap::new(),
driver_factory: None,
}
}
pub fn set_driver_factory(&mut self, factory: Box<dyn AsicDriverFactory>) {
self.driver_factory = Some(factory);
}
pub fn add_device_config(&mut self, device_id: String, config: AsicDeviceConfig) {
self.device_configs.insert(device_id, config);
}
pub async fn create_asic_device(
&self,
config: &AsicDeviceConfig,
) -> HardwareResult<AsicDevice> {
let mut device = AsicDevice::new(config.clone());
if let Some(factory) = &self.driver_factory {
if factory.is_available(&config.spec.asic_type) {
let driver = factory.create_driver(&config.spec.asic_type)?;
device.set_driver(driver);
}
}
Ok(device)
}
}
#[async_trait]
impl HardwareBackend for AsicBackend {
fn name(&self) -> &str {
&self.name
}
fn version(&self) -> &str {
&self.version
}
async fn discover_devices(&self) -> HardwareResult<Vec<Box<dyn HardwareDevice>>> {
let mut devices = Vec::new();
for (device_id, config) in &self.device_configs {
let device = self.create_asic_device(config).await?;
devices.push(Box::new(device) as Box<dyn HardwareDevice>);
}
Ok(devices)
}
async fn create_device(
&self,
config: &HardwareConfig,
) -> HardwareResult<Box<dyn HardwareDevice>> {
if config.hardware_type != HardwareType::ASIC {
return Err(TrustformersError::invalid_config(
"Invalid hardware type for ASIC backend".to_string(),
));
}
if let Some(asic_config) = self.device_configs.get(&config.device_id) {
let device = self.create_asic_device(asic_config).await?;
Ok(Box::new(device) as Box<dyn HardwareDevice>)
} else {
Err(TrustformersError::model_error(format!(
"ASIC device {} not found",
config.device_id
)))
}
}
fn is_compatible(&self, hardware_type: HardwareType) -> bool {
hardware_type == HardwareType::ASIC
}
fn supported_operations(&self) -> &[String] {
use std::sync::OnceLock;
static OPERATIONS: OnceLock<Vec<String>> = OnceLock::new();
OPERATIONS.get_or_init(|| {
vec![
"matmul".to_string(),
"conv2d".to_string(),
"activation".to_string(),
"pooling".to_string(),
"fft".to_string(),
"filter".to_string(),
"encrypt".to_string(),
"decrypt".to_string(),
]
})
}
fn validate_config(&self, config: &HardwareConfig) -> HardwareResult<()> {
if config.hardware_type != HardwareType::ASIC {
return Err(TrustformersError::invalid_config(
"Invalid hardware type for ASIC backend".to_string(),
));
}
if !self.device_configs.contains_key(&config.device_id) {
return Err(TrustformersError::invalid_config(format!(
"ASIC device configuration for {} not found",
config.device_id
)));
}
Ok(())
}
}
impl Default for AsicDeviceConfig {
fn default() -> Self {
Self {
base_config: HardwareConfig::default(),
spec: AsicSpec {
asic_type: AsicType::AIInference,
vendor: AsicVendor {
name: "Generic".to_string(),
id: 0,
driver_version: "1.0.0".to_string(),
firmware_version: "1.0.0".to_string(),
support_contact: None,
},
model: "Generic AI ASIC".to_string(),
revision: "1.0".to_string(),
process_node: Some(7),
die_size: Some(100.0),
package: Some("BGA".to_string()),
frequency_range: Some((1000, 2000)),
power_range: Some((10.0, 100.0)),
temperature_range: Some((-40.0, 85.0)),
},
clock_frequency: Some(1500),
voltage: Some(1.0),
power_limit: Some(75.0),
thermal_limit: Some(85.0),
memory_config: AsicMemoryConfig::default(),
instruction_set: Some("generic_v1".to_string()),
init_params: HashMap::new(),
}
}
}
impl Default for AsicMemoryConfig {
fn default() -> Self {
Self {
on_chip_memory: Some(1024 * 1024), off_chip_memory: Some(1024 * 1024 * 1024), memory_bandwidth: Some(100.0), memory_latency: Some(10.0), cache_config: CacheConfig::default(),
}
}
}
impl Default for CacheConfig {
fn default() -> Self {
Self {
l1_size: Some(64 * 1024), l2_size: Some(256 * 1024), l3_size: Some(1024 * 1024), line_size: Some(64), associativity: Some(8), }
}
}
impl std::fmt::Display for AsicType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
AsicType::AIInference => write!(f, "AI Inference"),
AsicType::NPU => write!(f, "NPU"),
AsicType::TPU => write!(f, "TPU"),
AsicType::DSP => write!(f, "DSP"),
AsicType::VPU => write!(f, "VPU"),
AsicType::Crypto => write!(f, "Crypto"),
AsicType::EdgeAI => write!(f, "Edge AI"),
AsicType::Custom(name) => write!(f, "Custom({})", name),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use tokio;
#[tokio::test]
async fn test_asic_device_creation() {
let config = AsicDeviceConfig::default();
let device = AsicDevice::new(config);
assert_eq!(device.hardware_type(), HardwareType::ASIC);
assert_eq!(device.device_id(), "default");
assert!(!device.is_available()); }
#[tokio::test]
async fn test_asic_device_initialization() {
let config = AsicDeviceConfig::default();
let mut device = AsicDevice::new(config);
let hw_config = HardwareConfig::default();
device.initialize(&hw_config).await.expect("async operation failed");
assert!(device.is_available());
assert!(device.status().online);
}
#[tokio::test]
async fn test_asic_memory_allocation() {
let config = AsicDeviceConfig::default();
let mut device = AsicDevice::new(config);
let memory = device.allocate_memory(1024).await.expect("async operation failed");
assert_eq!(memory.size, 1024);
assert_eq!(memory.memory_type, MemoryType::Local);
device.free_memory(memory).await.expect("async operation failed");
}
#[test]
fn test_asic_backend_compatibility() {
let backend = AsicBackend::new("test".to_string(), "1.0".to_string());
assert!(backend.is_compatible(HardwareType::ASIC));
assert!(!backend.is_compatible(HardwareType::CPU));
assert!(!backend.is_compatible(HardwareType::GPU));
}
#[test]
fn test_asic_type_display() {
assert_eq!(AsicType::AIInference.to_string(), "AI Inference");
assert_eq!(AsicType::NPU.to_string(), "NPU");
assert_eq!(
AsicType::Custom("MyASIC".to_string()).to_string(),
"Custom(MyASIC)"
);
}
#[test]
fn test_asic_capabilities_building() {
let config = AsicDeviceConfig::default();
let capabilities = AsicDevice::build_capabilities(&config);
assert!(capabilities.data_types.contains(&DataType::F32));
assert!(capabilities.data_types.contains(&DataType::F16));
assert!(capabilities.operations.contains(&"matmul".to_string()));
}
#[test]
fn test_asic_operation_sets() {
let config = AsicDeviceConfig::default();
let operation_sets = AsicDevice::build_operation_sets(&config);
assert!(!operation_sets.is_empty());
assert!(operation_sets.iter().any(|ops| ops.name == "ml_ops"));
}
#[test]
fn test_performance_monitor() {
let mut monitor = AsicPerformanceMonitor::new();
monitor.record_operation("matmul");
monitor.record_operation("matmul");
monitor.record_operation("conv2d");
monitor.record_error("timeout");
let op_stats = monitor.get_operation_stats();
assert_eq!(op_stats.get("matmul"), Some(&2));
assert_eq!(op_stats.get("conv2d"), Some(&1));
let error_stats = monitor.get_error_stats();
assert_eq!(error_stats.get("timeout"), Some(&1));
}
#[test]
fn test_asic_config_defaults() {
let config = AsicDeviceConfig::default();
assert_eq!(config.spec.asic_type, AsicType::AIInference);
assert_eq!(config.spec.vendor.name, "Generic");
assert_eq!(config.clock_frequency, Some(1500));
assert_eq!(config.memory_config.on_chip_memory, Some(1024 * 1024));
}
}