use crate::{MemoryOptimization, MobileBackend, MobileConfig, MobilePlatform};
use serde::{Deserialize, Serialize};
use trustformers_core::error::Result;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MobileDeviceInfo {
pub basic_info: BasicDeviceInfo,
pub platform: MobilePlatform,
pub cpu_info: CpuInfo,
pub memory_info: MemoryInfo,
pub gpu_info: Option<GpuInfo>,
pub npu_info: Option<NpuInfo>,
pub thermal_info: ThermalInfo,
pub power_info: PowerInfo,
pub available_backends: Vec<MobileBackend>,
pub performance_scores: PerformanceScores,
}
impl Default for MobileDeviceInfo {
fn default() -> Self {
Self {
basic_info: BasicDeviceInfo {
platform: MobilePlatform::Generic,
manufacturer: "Generic".to_string(),
model: "Test Device".to_string(),
os_version: "1.0.0".to_string(),
hardware_id: "test-device-001".to_string(),
device_generation: Some(2023),
},
platform: MobilePlatform::Generic,
cpu_info: CpuInfo {
architecture: "arm64".to_string(),
core_count: 4,
performance_cores: 2,
efficiency_cores: 2,
total_cores: 4,
max_frequency_mhz: Some(2400),
l1_cache_kb: Some(64),
l2_cache_kb: Some(512),
l3_cache_kb: Some(2048),
simd_support: SimdSupport::Basic,
features: vec!["neon".to_string()],
},
memory_info: MemoryInfo {
total_mb: 4096,
available_mb: 2048,
total_memory: 4096,
available_memory: 2048,
bandwidth_mbps: Some(25600),
memory_type: "LPDDR4".to_string(),
frequency_mhz: Some(1600),
is_low_memory_device: false,
},
gpu_info: None,
npu_info: None,
thermal_info: ThermalInfo {
current_state: ThermalState::Nominal,
state: ThermalState::Nominal,
throttling_supported: true,
temperature_sensors: Vec::new(),
thermal_zones: Vec::new(),
},
power_info: PowerInfo {
battery_capacity_mah: Some(3000),
battery_level_percent: Some(80),
battery_level: Some(80),
battery_health_percent: Some(100),
charging_status: ChargingStatus::NotCharging,
is_charging: false,
power_save_mode: false,
low_power_mode_available: true,
},
available_backends: vec![MobileBackend::CPU],
performance_scores: PerformanceScores::default(),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BasicDeviceInfo {
pub platform: MobilePlatform,
pub manufacturer: String,
pub model: String,
pub os_version: String,
pub hardware_id: String,
pub device_generation: Option<u32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CpuInfo {
pub architecture: String,
pub total_cores: usize,
pub core_count: usize,
pub performance_cores: usize,
pub efficiency_cores: usize,
pub max_frequency_mhz: Option<usize>,
pub l1_cache_kb: Option<usize>,
pub l2_cache_kb: Option<usize>,
pub l3_cache_kb: Option<usize>,
pub features: Vec<String>,
pub simd_support: SimdSupport,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum SimdSupport {
None,
Basic, Advanced, Cutting, }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MemoryInfo {
pub total_mb: usize,
pub available_mb: usize,
pub total_memory: usize,
pub available_memory: usize,
pub bandwidth_mbps: Option<usize>,
pub memory_type: String,
pub frequency_mhz: Option<usize>,
pub is_low_memory_device: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GpuInfo {
pub vendor: String,
pub model: String,
pub driver_version: String,
pub memory_mb: Option<usize>,
pub compute_units: Option<usize>,
pub supported_apis: Vec<GpuApi>,
pub performance_tier: GpuPerformanceTier,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum GpuApi {
OpenGLES2,
OpenGLES3,
OpenGLES31,
OpenCL,
Vulkan,
Vulkan10,
Vulkan11,
Vulkan12,
Metal2,
Metal3,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum GpuPerformanceTier {
Low,
Medium,
High,
Flagship,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NpuInfo {
pub vendor: String,
pub model: String,
pub version: String,
pub tops: Option<f32>,
pub supported_precisions: Vec<NpuPrecision>,
pub memory_bandwidth_mbps: Option<usize>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum NpuPrecision {
FP32,
FP16,
BF16,
INT8,
INT4,
INT1,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ThermalInfo {
pub current_state: ThermalState,
pub state: ThermalState,
pub throttling_supported: bool,
pub temperature_sensors: Vec<TemperatureSensor>,
pub thermal_zones: Vec<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum ThermalState {
Nominal,
Fair,
Serious,
Critical,
Emergency,
Shutdown,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemperatureSensor {
pub name: String,
pub temperature_celsius: Option<f32>,
pub max_temperature_celsius: Option<f32>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PowerInfo {
pub battery_capacity_mah: Option<usize>,
pub battery_level_percent: Option<u8>,
pub battery_level: Option<u8>,
pub battery_health_percent: Option<u8>,
pub charging_status: ChargingStatus,
pub is_charging: bool,
pub power_save_mode: bool,
pub low_power_mode_available: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ChargingStatus {
Unknown,
Charging,
Discharging,
NotCharging,
Full,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PerformanceScores {
pub cpu_single_core: Option<u32>,
pub cpu_multi_core: Option<u32>,
pub gpu_score: Option<u32>,
pub memory_score: Option<u32>,
pub overall_tier: PerformanceTier,
pub tier: PerformanceTier,
}
impl Default for PerformanceScores {
fn default() -> Self {
Self {
cpu_single_core: None,
cpu_multi_core: None,
gpu_score: None,
memory_score: None,
overall_tier: PerformanceTier::Budget,
tier: PerformanceTier::Budget,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
pub enum PerformanceTier {
VeryLow, Low, Budget, Medium, Mid, High, VeryHigh, Flagship, }
pub struct MobileDeviceDetector;
impl MobileDeviceDetector {
pub fn detect() -> Result<MobileDeviceInfo> {
let basic_info = Self::detect_basic_info()?;
let cpu_info = Self::detect_cpu_info()?;
let memory_info = Self::detect_memory_info()?;
let gpu_info = Self::detect_gpu_info();
let npu_info = Self::detect_npu_info();
let thermal_info = Self::detect_thermal_info()?;
let power_info = Self::detect_power_info()?;
let available_backends = Self::detect_available_backends(&basic_info, &gpu_info, &npu_info);
let performance_scores = Self::benchmark_performance(&cpu_info, &memory_info, &gpu_info)?;
Ok(MobileDeviceInfo {
basic_info: basic_info.clone(),
platform: basic_info.platform,
cpu_info,
memory_info,
gpu_info,
npu_info,
thermal_info,
power_info,
available_backends,
performance_scores,
})
}
pub fn generate_optimized_config(device_info: &MobileDeviceInfo) -> MobileConfig {
let mut config = match device_info.basic_info.platform {
MobilePlatform::Ios => MobileConfig::ios_optimized(),
MobilePlatform::Android => MobileConfig::android_optimized(),
MobilePlatform::Generic => MobileConfig::default(),
};
match device_info.performance_scores.overall_tier {
PerformanceTier::VeryLow | PerformanceTier::Low => {
Self::configure_for_budget_device(&mut config, device_info)
},
PerformanceTier::Budget => Self::configure_for_budget_device(&mut config, device_info),
PerformanceTier::Medium | PerformanceTier::Mid => {
Self::configure_for_mid_device(&mut config, device_info)
},
PerformanceTier::High => Self::configure_for_high_device(&mut config, device_info),
PerformanceTier::VeryHigh | PerformanceTier::Flagship => {
Self::configure_for_flagship_device(&mut config, device_info)
},
}
Self::adjust_for_thermal_state(&mut config, device_info.thermal_info.current_state);
Self::adjust_for_power_state(&mut config, &device_info.power_info);
Self::select_optimal_backend(&mut config, &device_info.available_backends);
config
}
#[cfg(target_os = "android")]
fn detect_basic_info() -> Result<BasicDeviceInfo> {
Ok(BasicDeviceInfo {
platform: MobilePlatform::Android,
manufacturer: Self::get_android_manufacturer(),
model: Self::get_android_model(),
os_version: Self::get_android_version(),
hardware_id: Self::get_android_hardware_id(),
device_generation: Self::estimate_android_generation(),
})
}
#[cfg(target_os = "ios")]
fn detect_basic_info() -> Result<BasicDeviceInfo> {
Ok(BasicDeviceInfo {
platform: MobilePlatform::Ios,
manufacturer: "Apple".to_string(),
model: Self::get_ios_model(),
os_version: Self::get_ios_version(),
hardware_id: Self::get_ios_hardware_id(),
device_generation: Self::estimate_ios_generation(),
})
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
fn detect_basic_info() -> Result<BasicDeviceInfo> {
Ok(BasicDeviceInfo {
platform: MobilePlatform::Generic,
manufacturer: "Unknown".to_string(),
model: "Generic Device".to_string(),
os_version: "Unknown".to_string(),
hardware_id: "unknown".to_string(),
device_generation: None,
})
}
fn detect_cpu_info() -> Result<CpuInfo> {
#[cfg(any(target_os = "android", target_os = "ios"))]
{
let total_cores = num_cpus::get();
let architecture = std::env::consts::ARCH.to_string();
#[cfg(target_os = "android")]
let (perf_cores, eff_cores, features) = Self::detect_android_cpu_details(total_cores);
#[cfg(target_os = "ios")]
let (perf_cores, eff_cores, features) = Self::detect_ios_cpu_details(total_cores);
let simd_support = Self::detect_simd_support(&architecture, &features);
Ok(CpuInfo {
architecture,
total_cores,
performance_cores: perf_cores,
efficiency_cores: eff_cores,
max_frequency_mhz: Self::detect_max_cpu_frequency(),
l1_cache_kb: Self::detect_l1_cache_size(),
l2_cache_kb: Self::detect_l2_cache_size(),
l3_cache_kb: Self::detect_l3_cache_size(),
features,
simd_support,
})
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{
Ok(CpuInfo {
architecture: std::env::consts::ARCH.to_string(),
total_cores: num_cpus::get(),
core_count: num_cpus::get(),
performance_cores: num_cpus::get() / 2,
efficiency_cores: num_cpus::get() / 2,
max_frequency_mhz: None,
l1_cache_kb: None,
l2_cache_kb: None,
l3_cache_kb: None,
features: vec![],
simd_support: SimdSupport::Basic,
})
}
}
fn detect_memory_info() -> Result<MemoryInfo> {
#[cfg(any(target_os = "android", target_os = "ios"))]
{
let (total_mb, available_mb) = Self::get_memory_info_platform_specific()?;
let bandwidth_mbps = Self::estimate_memory_bandwidth();
let memory_type = Self::detect_memory_type();
let frequency_mhz = Self::detect_memory_frequency();
let is_low_memory_device = total_mb < 2048;
Ok(MemoryInfo {
total_mb,
available_mb,
bandwidth_mbps,
memory_type,
frequency_mhz,
is_low_memory_device,
})
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{
Ok(MemoryInfo {
total_mb: 4096, available_mb: 2048,
total_memory: 4096,
available_memory: 2048,
bandwidth_mbps: None,
memory_type: "Unknown".to_string(),
frequency_mhz: None,
is_low_memory_device: false,
})
}
}
fn detect_gpu_info() -> Option<GpuInfo> {
#[cfg(target_os = "android")]
{
Self::detect_android_gpu_info()
}
#[cfg(target_os = "ios")]
{
Self::detect_ios_gpu_info()
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{
None
}
}
fn detect_npu_info() -> Option<NpuInfo> {
#[cfg(target_os = "android")]
{
Self::detect_android_npu_info()
}
#[cfg(target_os = "ios")]
{
Self::detect_ios_neural_engine_info()
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{
None
}
}
fn detect_thermal_info() -> Result<ThermalInfo> {
let current_state = Self::get_current_thermal_state();
let throttling_supported = Self::is_thermal_throttling_supported();
let temperature_sensors = Self::enumerate_temperature_sensors();
let thermal_zones = Self::enumerate_thermal_zones();
Ok(ThermalInfo {
current_state,
state: current_state,
throttling_supported,
temperature_sensors,
thermal_zones,
})
}
fn detect_power_info() -> Result<PowerInfo> {
let battery_info = Self::get_battery_info();
let charging_status = Self::get_charging_status();
let power_save_mode = Self::is_power_save_mode_active();
let low_power_mode_available = Self::is_low_power_mode_available();
Ok(PowerInfo {
battery_capacity_mah: battery_info.0,
battery_level_percent: battery_info.1,
battery_level: battery_info.1,
battery_health_percent: battery_info.2,
charging_status,
is_charging: matches!(charging_status, ChargingStatus::Charging),
power_save_mode,
low_power_mode_available,
})
}
fn detect_available_backends(
basic_info: &BasicDeviceInfo,
gpu_info: &Option<GpuInfo>,
npu_info: &Option<NpuInfo>,
) -> Vec<MobileBackend> {
let mut backends = vec![MobileBackend::CPU];
match basic_info.platform {
MobilePlatform::Ios => {
if npu_info.is_some() {
backends.push(MobileBackend::CoreML);
}
if gpu_info.is_some() {
backends.push(MobileBackend::GPU);
}
},
MobilePlatform::Android => {
if npu_info.is_some() {
backends.push(MobileBackend::NNAPI);
}
if gpu_info.is_some() {
backends.push(MobileBackend::GPU);
}
},
MobilePlatform::Generic => {
},
}
backends
}
fn benchmark_performance(
cpu_info: &CpuInfo,
memory_info: &MemoryInfo,
gpu_info: &Option<GpuInfo>,
) -> Result<PerformanceScores> {
let cpu_single_core = Self::benchmark_cpu_single_core();
let cpu_multi_core = Self::benchmark_cpu_multi_core(cpu_info.total_cores);
let gpu_score = gpu_info.as_ref().map(|_| Self::benchmark_gpu());
let memory_score = Self::benchmark_memory_bandwidth();
let overall_tier = Self::calculate_overall_tier(
cpu_single_core,
cpu_multi_core,
gpu_score,
memory_info.total_mb,
);
Ok(PerformanceScores {
cpu_single_core,
cpu_multi_core,
gpu_score,
memory_score,
overall_tier,
tier: overall_tier,
})
}
fn configure_for_budget_device(config: &mut MobileConfig, device_info: &MobileDeviceInfo) {
config.memory_optimization = MemoryOptimization::Maximum;
config.max_memory_mb = (device_info.memory_info.total_mb / 6).max(128); config.num_threads = 1;
config.enable_batching = false;
config.max_batch_size = 1;
if let Some(ref mut quant) = config.quantization.as_mut() {
quant.scheme = crate::MobileQuantizationScheme::Int4; quant.dynamic = true;
}
}
fn configure_for_mid_device(config: &mut MobileConfig, device_info: &MobileDeviceInfo) {
config.memory_optimization = MemoryOptimization::Balanced;
config.max_memory_mb = (device_info.memory_info.total_mb / 4).max(256);
config.num_threads = (device_info.cpu_info.performance_cores).max(1);
config.enable_batching = device_info.memory_info.total_mb >= 3072;
config.max_batch_size = if config.enable_batching { 2 } else { 1 };
}
fn configure_for_high_device(config: &mut MobileConfig, device_info: &MobileDeviceInfo) {
config.memory_optimization = MemoryOptimization::Balanced;
config.max_memory_mb = (device_info.memory_info.total_mb / 3).max(512);
config.num_threads = device_info.cpu_info.performance_cores + 1;
config.enable_batching = true;
config.max_batch_size = 4;
if let Some(ref mut quant) = config.quantization.as_mut() {
quant.scheme = crate::MobileQuantizationScheme::FP16; }
}
fn configure_for_flagship_device(config: &mut MobileConfig, device_info: &MobileDeviceInfo) {
config.memory_optimization = MemoryOptimization::Minimal;
config.max_memory_mb = (device_info.memory_info.total_mb / 2).max(1024);
config.num_threads = device_info.cpu_info.total_cores;
config.enable_batching = true;
config.max_batch_size = 8;
if let Some(ref mut quant) = config.quantization.as_mut() {
quant.scheme = crate::MobileQuantizationScheme::FP16;
quant.per_channel = true; }
}
fn adjust_for_thermal_state(config: &mut MobileConfig, thermal_state: ThermalState) {
match thermal_state {
ThermalState::Critical | ThermalState::Emergency => {
config.memory_optimization = MemoryOptimization::Maximum;
config.num_threads = 1;
config.enable_batching = false;
config.max_batch_size = 1;
},
ThermalState::Serious => {
config.num_threads = (config.num_threads / 2).max(1);
config.max_batch_size = (config.max_batch_size / 2).max(1);
},
ThermalState::Fair => {
config.num_threads = (config.num_threads * 3 / 4).max(1);
},
_ => {
},
}
}
fn adjust_for_power_state(config: &mut MobileConfig, power_info: &PowerInfo) {
if power_info.power_save_mode || power_info.battery_level_percent.unwrap_or(100) < 20 {
config.memory_optimization = MemoryOptimization::Maximum;
config.num_threads = 1;
config.enable_batching = false;
config.backend = MobileBackend::CPU; } else if power_info.battery_level_percent.unwrap_or(100) < 50 {
config.num_threads = (config.num_threads / 2).max(1);
config.max_batch_size = (config.max_batch_size / 2).max(1);
}
}
fn select_optimal_backend(config: &mut MobileConfig, available_backends: &[MobileBackend]) {
for &backend in available_backends {
match backend {
MobileBackend::CoreML | MobileBackend::NNAPI => {
config.backend = backend;
return;
},
MobileBackend::GPU if config.backend == MobileBackend::CPU => {
config.backend = backend;
},
_ => {},
}
}
}
#[cfg(target_os = "android")]
fn get_android_manufacturer() -> String {
"Unknown".to_string()
}
#[cfg(target_os = "android")]
fn get_android_model() -> String {
"Android Device".to_string()
}
#[cfg(target_os = "android")]
fn get_android_version() -> String {
"Unknown".to_string()
}
#[cfg(target_os = "android")]
fn get_android_hardware_id() -> String {
"unknown".to_string()
}
#[cfg(target_os = "android")]
fn estimate_android_generation() -> Option<u32> {
None
}
#[cfg(target_os = "android")]
fn detect_android_cpu_details(total_cores: usize) -> (usize, usize, Vec<String>) {
let perf_cores = if total_cores >= 8 { 4 } else { total_cores / 2 };
let eff_cores = total_cores - perf_cores;
let features = vec!["neon".to_string()]; (perf_cores, eff_cores, features)
}
#[cfg(target_os = "android")]
fn detect_android_gpu_info() -> Option<GpuInfo> {
Some(GpuInfo {
vendor: "Unknown".to_string(),
model: "Android GPU".to_string(),
driver_version: "Unknown".to_string(),
memory_mb: None,
compute_units: None,
supported_apis: vec![GpuApi::OpenGLES3],
performance_tier: GpuPerformanceTier::Medium,
})
}
#[cfg(target_os = "android")]
fn detect_android_npu_info() -> Option<NpuInfo> {
None
}
#[cfg(target_os = "ios")]
fn get_ios_model() -> String {
"iPhone".to_string()
}
#[cfg(target_os = "ios")]
fn get_ios_version() -> String {
"Unknown".to_string()
}
#[cfg(target_os = "ios")]
fn get_ios_hardware_id() -> String {
"unknown".to_string()
}
#[cfg(target_os = "ios")]
fn estimate_ios_generation() -> Option<u32> {
None
}
#[cfg(target_os = "ios")]
fn detect_ios_cpu_details(total_cores: usize) -> (usize, usize, Vec<String>) {
let perf_cores = if total_cores >= 6 { 2 } else { total_cores / 2 };
let eff_cores = total_cores - perf_cores;
let features = vec!["neon".to_string(), "fp16".to_string()];
(perf_cores, eff_cores, features)
}
#[cfg(target_os = "ios")]
fn detect_ios_gpu_info() -> Option<GpuInfo> {
Some(GpuInfo {
vendor: "Apple".to_string(),
model: "Apple GPU".to_string(),
driver_version: "Unknown".to_string(),
memory_mb: None,
compute_units: None,
supported_apis: vec![GpuApi::Metal3],
performance_tier: GpuPerformanceTier::High,
})
}
#[cfg(target_os = "ios")]
fn detect_ios_neural_engine_info() -> Option<NpuInfo> {
Some(NpuInfo {
vendor: "Apple".to_string(),
model: "Neural Engine".to_string(),
version: "Unknown".to_string(),
tops: Some(15.8), supported_precisions: vec![NpuPrecision::FP16, NpuPrecision::INT8],
memory_bandwidth_mbps: None,
})
}
fn detect_simd_support(architecture: &str, features: &[String]) -> SimdSupport {
if architecture.contains("arm") || architecture.contains("aarch64") {
if features.iter().any(|f| f.contains("fp16")) {
SimdSupport::Advanced
} else if features.iter().any(|f| f.contains("neon")) {
SimdSupport::Basic
} else {
SimdSupport::None
}
} else if architecture.contains("x86") {
if features.iter().any(|f| f.contains("avx")) {
SimdSupport::Advanced
} else if features.iter().any(|f| f.contains("sse")) {
SimdSupport::Basic
} else {
SimdSupport::None
}
} else {
SimdSupport::None
}
}
fn detect_max_cpu_frequency() -> Option<usize> {
None
}
fn detect_l1_cache_size() -> Option<usize> {
None
}
fn detect_l2_cache_size() -> Option<usize> {
None
}
fn detect_l3_cache_size() -> Option<usize> {
None
}
#[cfg(any(target_os = "android", target_os = "ios"))]
fn get_memory_info_platform_specific() -> Result<(usize, usize)> {
Ok((4096, 2048)) }
fn estimate_memory_bandwidth() -> Option<usize> {
None
}
fn detect_memory_type() -> String {
"Unknown".to_string()
}
fn detect_memory_frequency() -> Option<usize> {
None
}
fn get_current_thermal_state() -> ThermalState {
ThermalState::Nominal
}
fn is_thermal_throttling_supported() -> bool {
true
}
fn enumerate_temperature_sensors() -> Vec<TemperatureSensor> {
vec![]
}
fn enumerate_thermal_zones() -> Vec<String> {
vec![]
}
fn get_battery_info() -> (Option<usize>, Option<u8>, Option<u8>) {
(None, None, None)
}
fn get_charging_status() -> ChargingStatus {
ChargingStatus::Unknown
}
fn is_power_save_mode_active() -> bool {
false
}
fn is_low_power_mode_available() -> bool {
true
}
fn benchmark_cpu_single_core() -> Option<u32> {
Some(1000) }
fn benchmark_cpu_multi_core(cores: usize) -> Option<u32> {
Some((1000 * cores) as u32) }
fn benchmark_gpu() -> u32 {
2000 }
fn benchmark_memory_bandwidth() -> Option<u32> {
Some(1500) }
fn calculate_overall_tier(
cpu_single: Option<u32>,
cpu_multi: Option<u32>,
gpu_score: Option<u32>,
memory_mb: usize,
) -> PerformanceTier {
let cpu_score = cpu_single.unwrap_or(0) + cpu_multi.unwrap_or(0) / 4;
let gpu_score = gpu_score.unwrap_or(0);
let memory_factor = if memory_mb >= 8192 {
1.2
} else if memory_mb >= 4096 {
1.0
} else {
0.8
};
let overall_score = ((cpu_score + gpu_score) as f32 * memory_factor) as u32;
if overall_score >= 4000 {
PerformanceTier::Flagship
} else if overall_score >= 2500 {
PerformanceTier::High
} else if overall_score >= 1500 {
PerformanceTier::Mid
} else {
PerformanceTier::Budget
}
}
}
impl MobileDeviceInfo {
pub fn supports_feature(&self, feature: &str) -> bool {
match feature {
"fp16" => {
self.cpu_info.features.iter().any(|f| f.contains("fp16"))
|| self
.npu_info
.as_ref()
.is_some_and(|npu| npu.supported_precisions.contains(&NpuPrecision::FP16))
},
"int8" => true, "int4" => self.npu_info.is_some(),
"simd" => matches!(
self.cpu_info.simd_support,
SimdSupport::Basic | SimdSupport::Advanced | SimdSupport::Cutting
),
"gpu" => self.gpu_info.is_some(),
"npu" => self.npu_info.is_some(),
"vulkan" => self.gpu_info.as_ref().is_some_and(|gpu| {
gpu.supported_apis.iter().any(|api| {
matches!(api, GpuApi::Vulkan10 | GpuApi::Vulkan11 | GpuApi::Vulkan12)
})
}),
"metal" => self.gpu_info.as_ref().is_some_and(|gpu| {
gpu.supported_apis
.iter()
.any(|api| matches!(api, GpuApi::Metal2 | GpuApi::Metal3))
}),
_ => false,
}
}
pub fn get_recommended_memory_allocation(&self) -> usize {
let base_allocation = match self.performance_scores.overall_tier {
PerformanceTier::VeryLow => self.memory_info.total_mb / 16,
PerformanceTier::Low => self.memory_info.total_mb / 12,
PerformanceTier::Budget => self.memory_info.total_mb / 8,
PerformanceTier::Medium => self.memory_info.total_mb / 6,
PerformanceTier::Mid => self.memory_info.total_mb / 4,
PerformanceTier::High => self.memory_info.total_mb / 3,
PerformanceTier::VeryHigh => self.memory_info.total_mb / 2,
PerformanceTier::Flagship => self.memory_info.total_mb / 2,
};
let available_ratio =
self.memory_info.available_mb as f32 / self.memory_info.total_mb as f32;
let adjusted = (base_allocation as f32 * available_ratio) as usize;
adjusted.clamp(128, 2048) }
pub fn supports_on_device_training(&self) -> bool {
self.memory_info.total_mb >= 3072 && self.cpu_info.total_cores >= 4 && matches!(self.performance_scores.overall_tier, PerformanceTier::High | PerformanceTier::Flagship)
}
pub fn summary(&self) -> String {
format!(
"Device: {} {} | Platform: {:?} | Memory: {}MB/{} MB | CPU: {} cores ({} perf + {} eff) | GPU: {} | NPU: {} | Performance: {:?}",
self.basic_info.manufacturer,
self.basic_info.model,
self.basic_info.platform,
self.memory_info.available_mb,
self.memory_info.total_mb,
self.cpu_info.total_cores,
self.cpu_info.performance_cores,
self.cpu_info.efficiency_cores,
self.gpu_info.as_ref().map_or("None".to_string(), |gpu| format!("{} {}", gpu.vendor, gpu.model)),
self.npu_info.as_ref().map_or("None".to_string(), |npu| npu.model.clone()),
self.performance_scores.overall_tier
)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_device_detection() {
let device_info = MobileDeviceDetector::detect();
assert!(device_info.is_ok());
let info = device_info.expect("operation failed in test");
assert!(info.cpu_info.total_cores > 0);
assert!(info.memory_info.total_mb > 0);
assert!(!info.available_backends.is_empty());
}
#[test]
fn test_config_generation() {
let device_info = MobileDeviceDetector::detect().expect("operation failed in test");
let config = MobileDeviceDetector::generate_optimized_config(&device_info);
assert!(config.validate().is_ok());
assert!(config.max_memory_mb > 0);
assert!(config.get_thread_count() > 0);
}
#[test]
fn test_performance_tiers() {
let budget_tier = PerformanceTier::Budget;
let flagship_tier = PerformanceTier::Flagship;
assert_ne!(budget_tier, flagship_tier);
assert!(matches!(budget_tier, PerformanceTier::Budget));
}
#[test]
fn test_simd_support() {
let support = SimdSupport::Advanced;
assert!(matches!(support, SimdSupport::Advanced));
}
#[test]
fn test_thermal_states() {
let state = ThermalState::Nominal;
assert_eq!(state, ThermalState::Nominal);
}
#[test]
fn test_feature_support() {
let device_info = MobileDeviceDetector::detect().expect("operation failed in test");
let _simd_support = device_info.supports_feature("simd");
let _int8_support = device_info.supports_feature("int8");
}
#[test]
fn test_memory_allocation() {
let device_info = MobileDeviceDetector::detect().expect("operation failed in test");
let allocation = device_info.get_recommended_memory_allocation();
assert!(allocation >= 128);
assert!(allocation <= 2048);
}
}