Consistent formatting pass: line wrapping, import sorting, trailing whitespace removal, let-chain indentation, merged derive attributes, and unsafe block reformatting. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
1103 lines
36 KiB
Rust
1103 lines
36 KiB
Rust
//! Edge device capability detection and analysis
|
|
//!
|
|
//! This module provides comprehensive hardware capability detection and analysis
|
|
//! for edge computing deployments across diverse platforms including ARM, RISC-V,
|
|
//! WebAssembly, mobile GPUs, and `IoT` devices.
|
|
|
|
use crate::Result;
|
|
use std::collections::HashMap;
|
|
use tracing::info;
|
|
|
|
/// Edge device capability classes for adaptive optimization
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
pub enum EdgeClass {
|
|
/// High-end edge devices (server-class ARM, high-end mobile)
|
|
HighEnd,
|
|
/// Mid-range devices (standard mobile, tablet)
|
|
Mid,
|
|
/// Low-end devices (basic mobile, embedded)
|
|
Low,
|
|
/// Ultra-low power `IoT` devices
|
|
IoT,
|
|
}
|
|
|
|
/// Cross-platform device capabilities detected at runtime
|
|
#[derive(Debug, Clone)]
|
|
pub struct EdgeCapabilities {
|
|
/// Number of available compute units (CPU cores / GPU units)
|
|
pub compute_units: u32,
|
|
/// Available RAM in megabytes
|
|
pub memory_mb: u64,
|
|
/// SIMD instruction set support
|
|
pub simd_support: SIMDClass,
|
|
/// Power budget classification
|
|
pub power_budget: PowerClass,
|
|
/// Network connectivity type
|
|
pub network: NetworkClass,
|
|
/// Edge device class derived from capabilities
|
|
pub edge_class: EdgeClass,
|
|
/// Platform-specific optimization flags
|
|
pub optimization_flags: HashMap<String, String>,
|
|
}
|
|
|
|
/// SIMD instruction set classifications
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
pub enum SIMDClass {
|
|
/// ARM NEON (mobile/server ARM)
|
|
NEON,
|
|
/// Intel/AMD AVX2/AVX-512
|
|
AVX,
|
|
/// RISC-V Vector Extension
|
|
RVV,
|
|
/// WebAssembly SIMD
|
|
WASM_SIMD,
|
|
/// No SIMD support
|
|
None,
|
|
}
|
|
|
|
/// Power budget classifications for battery-aware optimization
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
pub enum PowerClass {
|
|
/// Wall power / unlimited
|
|
Unlimited,
|
|
/// High battery capacity
|
|
HighBattery,
|
|
/// Standard mobile battery
|
|
StandardBattery,
|
|
/// Low power `IoT`
|
|
LowPower,
|
|
/// Ultra-low power microcontroller
|
|
UltraLowPower,
|
|
}
|
|
|
|
/// Network connectivity classes for bandwidth-aware optimization
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
pub enum NetworkClass {
|
|
/// High-speed WiFi/Ethernet
|
|
HighSpeed,
|
|
/// Standard `WiFi`
|
|
WiFi,
|
|
/// Cellular (4G/5G)
|
|
Cellular,
|
|
/// Low-bandwidth (`LoRa`, Zigbee)
|
|
LowBandwidth,
|
|
/// Offline/air-gapped
|
|
Offline,
|
|
}
|
|
|
|
/// Cache hierarchy information
|
|
#[derive(Debug, Clone)]
|
|
pub struct CacheInfo {
|
|
/// L1 cache size in KB
|
|
pub l1_cache_kb: u32,
|
|
/// L2 cache size in KB
|
|
pub l2_cache_kb: u32,
|
|
/// L3 cache size in KB
|
|
pub l3_cache_kb: u32,
|
|
}
|
|
|
|
/// GPU information for mobile devices
|
|
#[derive(Debug, Clone)]
|
|
pub struct GpuInfo {
|
|
/// GPU vendor
|
|
pub vendor: String,
|
|
/// GPU memory in MB
|
|
pub memory_mb: u32,
|
|
}
|
|
|
|
/// CUDA capability information
|
|
#[derive(Debug, Clone)]
|
|
pub struct CudaInfo {
|
|
/// Compute capability version
|
|
pub compute_capability: String,
|
|
/// GPU memory in GB
|
|
pub memory_gb: u32,
|
|
}
|
|
|
|
/// Battery information
|
|
#[derive(Debug, Clone)]
|
|
pub struct BatteryInfo {
|
|
/// Battery level (0-100)
|
|
pub level: u32,
|
|
/// Whether battery is charging
|
|
pub charging: bool,
|
|
}
|
|
|
|
/// Edge capability detection and analysis
|
|
pub struct EdgeCapabilityDetector;
|
|
|
|
impl EdgeCapabilityDetector {
|
|
/// Comprehensive device capability detection across all platforms
|
|
pub fn detect_edge_capabilities() -> Result<EdgeCapabilities> {
|
|
info!("Starting comprehensive hardware capability profiling");
|
|
|
|
let mut capabilities = EdgeCapabilities {
|
|
compute_units: Self::detect_compute_units(),
|
|
memory_mb: Self::detect_memory_mb(),
|
|
simd_support: Self::detect_simd_support(),
|
|
power_budget: Self::detect_power_budget(),
|
|
network: Self::detect_network_class(),
|
|
edge_class: EdgeClass::Mid, // Will be updated below
|
|
optimization_flags: HashMap::new(),
|
|
};
|
|
|
|
// Enhanced hardware profiling
|
|
Self::profile_cpu_capabilities(&mut capabilities)?;
|
|
Self::profile_memory_hierarchy(&mut capabilities)?;
|
|
Self::profile_gpu_capabilities(&mut capabilities)?;
|
|
Self::profile_power_characteristics(&mut capabilities)?;
|
|
Self::benchmark_compute_performance(&mut capabilities)?;
|
|
|
|
// Classify edge device based on detected capabilities
|
|
capabilities.edge_class = Self::classify_device_class(&capabilities);
|
|
|
|
// Set comprehensive optimization flags
|
|
Self::configure_optimization_flags(&mut capabilities);
|
|
|
|
info!(
|
|
"Advanced hardware profiling complete: class={:?}, cores={}, memory={}MB, simd={:?}",
|
|
capabilities.edge_class,
|
|
capabilities.compute_units,
|
|
capabilities.memory_mb,
|
|
capabilities.simd_support
|
|
);
|
|
|
|
Ok(capabilities)
|
|
}
|
|
|
|
/// Profile CPU capabilities including architecture-specific features
|
|
pub fn profile_cpu_capabilities(capabilities: &mut EdgeCapabilities) -> Result<()> {
|
|
info!("Profiling CPU capabilities");
|
|
|
|
// Detect CPU architecture
|
|
#[cfg(target_arch = "aarch64")]
|
|
{
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("cpu_arch".to_string(), "aarch64".to_string());
|
|
|
|
// ARM-specific feature detection
|
|
#[cfg(target_feature = "neon")]
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("neon_available".to_string(), "true".to_string());
|
|
|
|
#[cfg(target_feature = "fp16")]
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("fp16_native".to_string(), "true".to_string());
|
|
|
|
#[cfg(target_feature = "dotprod")]
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("dotprod_available".to_string(), "true".to_string());
|
|
|
|
// Check for ARM scalable vector extensions
|
|
if Self::check_arm_sve() {
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("sve_available".to_string(), "true".to_string());
|
|
}
|
|
}
|
|
|
|
#[cfg(target_arch = "riscv64")]
|
|
{
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("cpu_arch".to_string(), "riscv64".to_string());
|
|
|
|
// RISC-V vector extension detection
|
|
if Self::check_riscv_vector_extensions() {
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("rvv_available".to_string(), "true".to_string());
|
|
let vlen = Self::detect_riscv_vlen();
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("rvv_vlen".to_string(), vlen.to_string());
|
|
}
|
|
}
|
|
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
{
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("cpu_arch".to_string(), "x86_64".to_string());
|
|
|
|
// x86 feature detection
|
|
#[cfg(target_feature = "avx2")]
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("avx2_available".to_string(), "true".to_string());
|
|
|
|
#[cfg(target_feature = "avx512f")]
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("avx512_available".to_string(), "true".to_string());
|
|
|
|
#[cfg(target_feature = "fma")]
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("fma_available".to_string(), "true".to_string());
|
|
}
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
{
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("cpu_arch".to_string(), "wasm32".to_string());
|
|
|
|
#[cfg(target_feature = "simd128")]
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("wasm_simd_available".to_string(), "true".to_string());
|
|
}
|
|
|
|
// Detect cache hierarchy
|
|
let cache_info = Self::detect_cache_hierarchy();
|
|
capabilities.optimization_flags.insert(
|
|
"l1_cache_kb".to_string(),
|
|
cache_info.l1_cache_kb.to_string(),
|
|
);
|
|
capabilities.optimization_flags.insert(
|
|
"l2_cache_kb".to_string(),
|
|
cache_info.l2_cache_kb.to_string(),
|
|
);
|
|
capabilities.optimization_flags.insert(
|
|
"l3_cache_kb".to_string(),
|
|
cache_info.l3_cache_kb.to_string(),
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Profile memory hierarchy and bandwidth characteristics
|
|
pub fn profile_memory_hierarchy(capabilities: &mut EdgeCapabilities) -> Result<()> {
|
|
info!("Profiling memory hierarchy");
|
|
|
|
// Memory bandwidth benchmark
|
|
let memory_bandwidth = Self::benchmark_memory_bandwidth();
|
|
capabilities.optimization_flags.insert(
|
|
"memory_bandwidth_gbps".to_string(),
|
|
memory_bandwidth.to_string(),
|
|
);
|
|
|
|
// Memory latency characteristics
|
|
let memory_latency = Self::benchmark_memory_latency();
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("memory_latency_ns".to_string(), memory_latency.to_string());
|
|
|
|
// NUMA topology detection
|
|
#[cfg(target_os = "linux")]
|
|
{
|
|
let numa_nodes = Self::detect_numa_topology();
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("numa_nodes".to_string(), numa_nodes.to_string());
|
|
}
|
|
|
|
// Large page support
|
|
if Self::check_large_page_support() {
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("large_pages_available".to_string(), "true".to_string());
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Profile GPU capabilities for mobile and discrete GPUs
|
|
pub fn profile_gpu_capabilities(capabilities: &mut EdgeCapabilities) -> Result<()> {
|
|
info!("Profiling GPU capabilities");
|
|
|
|
// Check for mobile GPU
|
|
#[cfg(target_os = "android")]
|
|
{
|
|
let gpu_info = Self::detect_android_gpu();
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("mobile_gpu".to_string(), gpu_info.vendor);
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("gpu_memory_mb".to_string(), gpu_info.memory_mb.to_string());
|
|
}
|
|
|
|
// Check for discrete GPU
|
|
#[cfg(feature = "cuda")]
|
|
{
|
|
if Self::check_cuda_available() {
|
|
let cuda_info = Self::detect_cuda_capabilities();
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("cuda_available".to_string(), "true".to_string());
|
|
capabilities.optimization_flags.insert(
|
|
"cuda_compute_capability".to_string(),
|
|
cuda_info.compute_capability,
|
|
);
|
|
capabilities.optimization_flags.insert(
|
|
"cuda_memory_gb".to_string(),
|
|
cuda_info.memory_gb.to_string(),
|
|
);
|
|
}
|
|
}
|
|
|
|
// Check for Metal (macOS/iOS)
|
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
|
{
|
|
if Self::check_metal_available() {
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("metal_available".to_string(), "true".to_string());
|
|
}
|
|
}
|
|
|
|
// Check for Vulkan compute
|
|
if Self::check_vulkan_compute() {
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("vulkan_compute_available".to_string(), "true".to_string());
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Profile power characteristics and thermal limits
|
|
pub fn profile_power_characteristics(capabilities: &mut EdgeCapabilities) -> Result<()> {
|
|
info!("Profiling power characteristics");
|
|
|
|
// Battery status detection
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
|
{
|
|
let battery_info = Self::detect_battery_status();
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("battery_level".to_string(), battery_info.level.to_string());
|
|
capabilities.optimization_flags.insert(
|
|
"battery_charging".to_string(),
|
|
battery_info.charging.to_string(),
|
|
);
|
|
}
|
|
|
|
// Thermal throttling detection
|
|
let thermal_state = Self::detect_thermal_state();
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("thermal_state".to_string(), thermal_state.to_string());
|
|
|
|
// Power governor detection (Linux)
|
|
#[cfg(target_os = "linux")]
|
|
{
|
|
let power_governor = Self::detect_power_governor();
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("power_governor".to_string(), power_governor);
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Benchmark actual compute performance
|
|
pub fn benchmark_compute_performance(capabilities: &mut EdgeCapabilities) -> Result<()> {
|
|
info!("Benchmarking compute performance");
|
|
|
|
// Matrix multiplication benchmark
|
|
let gemm_gflops = Self::benchmark_gemm_performance();
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("gemm_gflops".to_string(), gemm_gflops.to_string());
|
|
|
|
// SIMD performance benchmark
|
|
match capabilities.simd_support {
|
|
SIMDClass::NEON => {
|
|
let neon_gflops = Self::benchmark_neon_performance();
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("neon_gflops".to_string(), neon_gflops.to_string());
|
|
}
|
|
SIMDClass::RVV => {
|
|
let rvv_gflops = Self::benchmark_rvv_performance();
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("rvv_gflops".to_string(), rvv_gflops.to_string());
|
|
}
|
|
SIMDClass::WASM_SIMD => {
|
|
let wasm_simd_gflops = Self::benchmark_wasm_simd_performance();
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("wasm_simd_gflops".to_string(), wasm_simd_gflops.to_string());
|
|
}
|
|
SIMDClass::AVX => {
|
|
let avx_gflops = Self::benchmark_avx_performance();
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("avx_gflops".to_string(), avx_gflops.to_string());
|
|
}
|
|
SIMDClass::None => {
|
|
let scalar_gflops = Self::benchmark_scalar_performance();
|
|
capabilities
|
|
.optimization_flags
|
|
.insert("scalar_gflops".to_string(), scalar_gflops.to_string());
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
/// Classify device class based on comprehensive profiling
|
|
#[must_use]
|
|
pub fn classify_device_class(capabilities: &EdgeCapabilities) -> EdgeClass {
|
|
let compute_score = capabilities.compute_units as f32;
|
|
let memory_score = (capabilities.memory_mb as f32 / 1024.0).min(16.0); // Cap at 16GB for scoring
|
|
|
|
// Get performance scores from benchmarks
|
|
let gemm_score = capabilities
|
|
.optimization_flags
|
|
.get("gemm_gflops")
|
|
.and_then(|s| s.parse::<f32>().ok())
|
|
.unwrap_or(1.0);
|
|
|
|
let power_score = match capabilities.power_budget {
|
|
PowerClass::Unlimited => 4.0,
|
|
PowerClass::HighBattery => 3.0,
|
|
PowerClass::StandardBattery => 2.0,
|
|
PowerClass::LowPower => 1.0,
|
|
PowerClass::UltraLowPower => 0.5,
|
|
};
|
|
|
|
// Weighted scoring system
|
|
let total_score =
|
|
0.3 * compute_score + 0.3 * memory_score + 0.2 * gemm_score + 0.2 * power_score;
|
|
|
|
match total_score {
|
|
score if score >= 12.0 => EdgeClass::HighEnd,
|
|
score if score >= 6.0 => EdgeClass::Mid,
|
|
score if score >= 2.0 => EdgeClass::Low,
|
|
_ => EdgeClass::IoT,
|
|
}
|
|
}
|
|
|
|
/// Configure comprehensive optimization flags
|
|
pub fn configure_optimization_flags(capabilities: &mut EdgeCapabilities) {
|
|
// Platform-specific optimizations
|
|
capabilities.optimization_flags.insert(
|
|
"use_neon".to_string(),
|
|
(capabilities.simd_support == SIMDClass::NEON).to_string(),
|
|
);
|
|
capabilities.optimization_flags.insert(
|
|
"use_rvv".to_string(),
|
|
(capabilities.simd_support == SIMDClass::RVV).to_string(),
|
|
);
|
|
capabilities.optimization_flags.insert(
|
|
"use_wasm_simd".to_string(),
|
|
(capabilities.simd_support == SIMDClass::WASM_SIMD).to_string(),
|
|
);
|
|
capabilities.optimization_flags.insert(
|
|
"use_avx".to_string(),
|
|
(capabilities.simd_support == SIMDClass::AVX).to_string(),
|
|
);
|
|
|
|
// Battery-aware optimizations
|
|
capabilities.optimization_flags.insert(
|
|
"battery_optimization".to_string(),
|
|
matches!(
|
|
capabilities.power_budget,
|
|
PowerClass::StandardBattery | PowerClass::LowPower
|
|
)
|
|
.to_string(),
|
|
);
|
|
|
|
// Memory optimizations
|
|
capabilities.optimization_flags.insert(
|
|
"memory_constrained".to_string(),
|
|
(capabilities.memory_mb < 2048).to_string(),
|
|
);
|
|
|
|
// Compute optimizations
|
|
capabilities.optimization_flags.insert(
|
|
"parallel_capable".to_string(),
|
|
(capabilities.compute_units > 1).to_string(),
|
|
);
|
|
}
|
|
|
|
// Hardware detection helper methods (placeholder implementations)
|
|
fn check_arm_sve() -> bool {
|
|
false
|
|
}
|
|
fn check_riscv_vector_extensions() -> bool {
|
|
true
|
|
} // Assume available for RISC-V
|
|
fn detect_riscv_vlen() -> u32 {
|
|
128
|
|
} // Common VLEN
|
|
fn detect_cache_hierarchy() -> CacheInfo {
|
|
CacheInfo {
|
|
l1_cache_kb: 32,
|
|
l2_cache_kb: 256,
|
|
l3_cache_kb: 2048,
|
|
}
|
|
}
|
|
fn benchmark_memory_bandwidth() -> f32 {
|
|
25.0
|
|
} // GB/s
|
|
fn benchmark_memory_latency() -> u32 {
|
|
100
|
|
} // ns
|
|
fn detect_numa_topology() -> u32 {
|
|
1
|
|
}
|
|
fn check_large_page_support() -> bool {
|
|
false
|
|
}
|
|
fn detect_android_gpu() -> GpuInfo {
|
|
GpuInfo {
|
|
vendor: "Mali".to_string(),
|
|
memory_mb: 1024,
|
|
}
|
|
}
|
|
fn check_cuda_available() -> bool {
|
|
false
|
|
}
|
|
fn detect_cuda_capabilities() -> CudaInfo {
|
|
CudaInfo {
|
|
compute_capability: "8.0".to_string(),
|
|
memory_gb: 8,
|
|
}
|
|
}
|
|
fn check_metal_available() -> bool {
|
|
false
|
|
}
|
|
fn check_vulkan_compute() -> bool {
|
|
false
|
|
}
|
|
fn detect_battery_status() -> BatteryInfo {
|
|
BatteryInfo {
|
|
level: 80,
|
|
charging: false,
|
|
}
|
|
}
|
|
fn detect_thermal_state() -> u32 {
|
|
0
|
|
} // 0 = normal
|
|
fn detect_power_governor() -> String {
|
|
"performance".to_string()
|
|
}
|
|
fn benchmark_gemm_performance() -> f32 {
|
|
10.0
|
|
} // GFLOPS
|
|
fn benchmark_neon_performance() -> f32 {
|
|
15.0
|
|
}
|
|
fn benchmark_rvv_performance() -> f32 {
|
|
25.0
|
|
}
|
|
fn benchmark_wasm_simd_performance() -> f32 {
|
|
5.0
|
|
}
|
|
fn benchmark_avx_performance() -> f32 {
|
|
30.0
|
|
}
|
|
fn benchmark_scalar_performance() -> f32 {
|
|
2.0
|
|
}
|
|
|
|
/// Detect available compute units (CPU cores, GPU units)
|
|
#[must_use]
|
|
pub fn detect_compute_units() -> u32 {
|
|
#[cfg(feature = "std")]
|
|
{
|
|
std::thread::available_parallelism()
|
|
.map(|p| p.get() as u32)
|
|
.unwrap_or(1)
|
|
}
|
|
#[cfg(not(feature = "std"))]
|
|
{
|
|
1 // Conservative default for no_std environments
|
|
}
|
|
}
|
|
|
|
/// Detect available system memory in megabytes
|
|
#[must_use]
|
|
pub fn detect_memory_mb() -> u64 {
|
|
#[cfg(all(feature = "std", target_os = "linux"))]
|
|
{
|
|
if let Ok(contents) = std::fs::read_to_string("/proc/meminfo") {
|
|
for line in contents.lines() {
|
|
if line.starts_with("MemTotal:") {
|
|
if let Some(kb_str) = line.split_whitespace().nth(1) {
|
|
if let Ok(kb) = kb_str.parse::<u64>() {
|
|
return kb / 1024; // Convert KB to MB
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Conservative defaults for other platforms or when detection fails
|
|
#[cfg(target_arch = "wasm32")]
|
|
return 1024; // 1GB typical for WASM
|
|
|
|
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
|
|
return 2048; // 2GB typical for ARM devices
|
|
|
|
#[cfg(target_arch = "riscv64")]
|
|
return 512; // 512MB typical for RISC-V
|
|
|
|
4096 // 4GB default
|
|
}
|
|
|
|
/// Detect SIMD instruction set support
|
|
#[must_use]
|
|
pub fn detect_simd_support() -> SIMDClass {
|
|
#[cfg(target_arch = "aarch64")]
|
|
return SIMDClass::NEON;
|
|
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
{
|
|
#[cfg(target_feature = "avx2")]
|
|
return SIMDClass::AVX;
|
|
}
|
|
|
|
#[cfg(target_arch = "riscv64")]
|
|
return SIMDClass::RVV;
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
{
|
|
#[cfg(target_feature = "simd128")]
|
|
return SIMDClass::WASM_SIMD;
|
|
}
|
|
|
|
SIMDClass::None
|
|
}
|
|
|
|
/// Detect power budget classification
|
|
#[must_use]
|
|
pub fn detect_power_budget() -> PowerClass {
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
|
return PowerClass::StandardBattery;
|
|
|
|
#[cfg(target_arch = "wasm32")]
|
|
return PowerClass::StandardBattery; // Browser typically battery-powered
|
|
|
|
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
|
|
{
|
|
// Check if running on battery
|
|
#[cfg(target_os = "linux")]
|
|
{
|
|
if std::path::Path::new("/sys/class/power_supply/BAT0").exists() {
|
|
return PowerClass::HighBattery;
|
|
}
|
|
}
|
|
|
|
return PowerClass::Unlimited; // Assume wall power for desktop/server
|
|
}
|
|
|
|
PowerClass::LowPower // Conservative default for embedded
|
|
}
|
|
|
|
/// Detect network connectivity class
|
|
#[must_use]
|
|
pub fn detect_network_class() -> NetworkClass {
|
|
#[cfg(target_arch = "wasm32")]
|
|
return NetworkClass::WiFi; // Browser typically WiFi
|
|
|
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
|
return NetworkClass::Cellular; // Mobile typically cellular
|
|
|
|
#[cfg(any(target_os = "linux", target_os = "windows", target_os = "macos"))]
|
|
return NetworkClass::HighSpeed; // Desktop/server high-speed
|
|
|
|
NetworkClass::LowBandwidth // Conservative for embedded
|
|
}
|
|
}
|
|
|
|
#[cfg(all(test, feature = "disabled_tests"))]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_edge_capabilities_detection() {
|
|
// Test comprehensive capability detection
|
|
let capabilities = EdgeCapabilityDetector::detect_edge_capabilities().unwrap();
|
|
assert!(capabilities.compute_units > 0);
|
|
assert!(capabilities.memory_mb > 0);
|
|
assert!(matches!(
|
|
capabilities.edge_class,
|
|
EdgeClass::HighEnd | EdgeClass::Mid | EdgeClass::Low | EdgeClass::IoT
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn test_cpu_capability_profiling() {
|
|
let mut capabilities = EdgeCapabilities {
|
|
compute_units: 4,
|
|
memory_mb: 2048,
|
|
simd_support: SIMDClass::None,
|
|
power_budget: PowerClass::StandardBattery,
|
|
network: NetworkClass::WiFi,
|
|
edge_class: EdgeClass::Mid,
|
|
optimization_flags: HashMap::new(),
|
|
};
|
|
|
|
EdgeCapabilityDetector::profile_cpu_capabilities(&mut capabilities).unwrap();
|
|
|
|
// Verify CPU profiling populates optimization flags
|
|
assert!(capabilities.optimization_flags.contains_key("cpu_arch"));
|
|
assert!(capabilities.optimization_flags.contains_key("gemm_gflops"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_memory_hierarchy_profiling() {
|
|
let mut capabilities = EdgeCapabilities {
|
|
compute_units: 8,
|
|
memory_mb: 16384,
|
|
simd_support: SIMDClass::AVX,
|
|
power_budget: PowerClass::Unlimited,
|
|
network: NetworkClass::HighSpeed,
|
|
edge_class: EdgeClass::HighEnd,
|
|
optimization_flags: HashMap::new(),
|
|
};
|
|
|
|
EdgeCapabilityDetector::profile_memory_hierarchy(&mut capabilities).unwrap();
|
|
|
|
// Verify memory profiling populates bandwidth and latency info
|
|
assert!(
|
|
capabilities
|
|
.optimization_flags
|
|
.contains_key("memory_bandwidth_gbps")
|
|
);
|
|
assert!(
|
|
capabilities
|
|
.optimization_flags
|
|
.contains_key("memory_latency_ns")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_gpu_capability_profiling() {
|
|
let mut capabilities = EdgeCapabilities {
|
|
compute_units: 4,
|
|
memory_mb: 4096,
|
|
simd_support: SIMDClass::NEON,
|
|
power_budget: PowerClass::HighBattery,
|
|
network: NetworkClass::WiFi,
|
|
edge_class: EdgeClass::Mid,
|
|
optimization_flags: HashMap::new(),
|
|
};
|
|
|
|
EdgeCapabilityDetector::profile_gpu_capabilities(&mut capabilities).unwrap();
|
|
|
|
// GPU profiling should complete without error
|
|
// Specific GPU flags depend on platform availability
|
|
}
|
|
|
|
#[test]
|
|
fn test_power_characteristics_profiling() {
|
|
let mut capabilities = EdgeCapabilities {
|
|
compute_units: 2,
|
|
memory_mb: 1024,
|
|
simd_support: SIMDClass::None,
|
|
power_budget: PowerClass::LowPower,
|
|
network: NetworkClass::LowBandwidth,
|
|
edge_class: EdgeClass::IoT,
|
|
optimization_flags: HashMap::new(),
|
|
};
|
|
|
|
EdgeCapabilityDetector::profile_power_characteristics(&mut capabilities).unwrap();
|
|
|
|
// Verify power profiling populates thermal and battery info
|
|
assert!(
|
|
capabilities
|
|
.optimization_flags
|
|
.contains_key("thermal_state")
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_compute_performance_benchmarking() {
|
|
let mut capabilities = EdgeCapabilities {
|
|
compute_units: 8,
|
|
memory_mb: 8192,
|
|
simd_support: SIMDClass::NEON,
|
|
power_budget: PowerClass::HighBattery,
|
|
network: NetworkClass::WiFi,
|
|
edge_class: EdgeClass::HighEnd,
|
|
optimization_flags: HashMap::new(),
|
|
};
|
|
|
|
EdgeCapabilityDetector::benchmark_compute_performance(&mut capabilities).unwrap();
|
|
|
|
// Verify performance benchmarking populates GFLOPS metrics
|
|
assert!(capabilities.optimization_flags.contains_key("gemm_gflops"));
|
|
|
|
match capabilities.simd_support {
|
|
SIMDClass::NEON => assert!(capabilities.optimization_flags.contains_key("neon_gflops")),
|
|
SIMDClass::RVV => assert!(capabilities.optimization_flags.contains_key("rvv_gflops")),
|
|
SIMDClass::WASM_SIMD => assert!(
|
|
capabilities
|
|
.optimization_flags
|
|
.contains_key("wasm_simd_gflops")
|
|
),
|
|
SIMDClass::AVX => assert!(capabilities.optimization_flags.contains_key("avx_gflops")),
|
|
SIMDClass::None => assert!(
|
|
capabilities
|
|
.optimization_flags
|
|
.contains_key("scalar_gflops")
|
|
),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_device_class_classification_high_end() {
|
|
let capabilities = EdgeCapabilities {
|
|
compute_units: 12,
|
|
memory_mb: 16384,
|
|
simd_support: SIMDClass::AVX,
|
|
power_budget: PowerClass::Unlimited,
|
|
network: NetworkClass::HighSpeed,
|
|
edge_class: EdgeClass::Mid, // Will be reclassified
|
|
optimization_flags: {
|
|
let mut flags = HashMap::new();
|
|
flags.insert("gemm_gflops".to_string(), "50.0".to_string());
|
|
flags
|
|
},
|
|
};
|
|
|
|
let classified = EdgeCapabilityDetector::classify_device_class(&capabilities);
|
|
assert_eq!(classified, EdgeClass::HighEnd);
|
|
}
|
|
|
|
#[test]
|
|
fn test_device_class_classification_iot() {
|
|
let capabilities = EdgeCapabilities {
|
|
compute_units: 1,
|
|
memory_mb: 32,
|
|
simd_support: SIMDClass::None,
|
|
power_budget: PowerClass::UltraLowPower,
|
|
network: NetworkClass::LowBandwidth,
|
|
edge_class: EdgeClass::Mid, // Will be reclassified
|
|
optimization_flags: {
|
|
let mut flags = HashMap::new();
|
|
flags.insert("gemm_gflops".to_string(), "0.5".to_string());
|
|
flags
|
|
},
|
|
};
|
|
|
|
let classified = EdgeCapabilityDetector::classify_device_class(&capabilities);
|
|
assert_eq!(classified, EdgeClass::IoT);
|
|
}
|
|
|
|
#[test]
|
|
fn test_device_class_classification_mid_range() {
|
|
let capabilities = EdgeCapabilities {
|
|
compute_units: 4,
|
|
memory_mb: 4096,
|
|
simd_support: SIMDClass::NEON,
|
|
power_budget: PowerClass::StandardBattery,
|
|
network: NetworkClass::WiFi,
|
|
edge_class: EdgeClass::Low, // Will be reclassified
|
|
optimization_flags: {
|
|
let mut flags = HashMap::new();
|
|
flags.insert("gemm_gflops".to_string(), "10.0".to_string());
|
|
flags
|
|
},
|
|
};
|
|
|
|
let classified = EdgeCapabilityDetector::classify_device_class(&capabilities);
|
|
assert_eq!(classified, EdgeClass::Mid);
|
|
}
|
|
|
|
#[test]
|
|
fn test_optimization_flags_configuration() {
|
|
let mut capabilities = EdgeCapabilities {
|
|
compute_units: 8,
|
|
memory_mb: 8192,
|
|
simd_support: SIMDClass::NEON,
|
|
power_budget: PowerClass::StandardBattery,
|
|
network: NetworkClass::WiFi,
|
|
edge_class: EdgeClass::HighEnd,
|
|
optimization_flags: HashMap::new(),
|
|
};
|
|
|
|
EdgeCapabilityDetector::configure_optimization_flags(&mut capabilities);
|
|
|
|
// Verify SIMD-specific flags are set
|
|
assert_eq!(
|
|
capabilities.optimization_flags.get("use_neon"),
|
|
Some(&"true".to_string())
|
|
);
|
|
assert_eq!(
|
|
capabilities.optimization_flags.get("use_rvv"),
|
|
Some(&"false".to_string())
|
|
);
|
|
assert_eq!(
|
|
capabilities.optimization_flags.get("use_wasm_simd"),
|
|
Some(&"false".to_string())
|
|
);
|
|
assert_eq!(
|
|
capabilities.optimization_flags.get("use_avx"),
|
|
Some(&"false".to_string())
|
|
);
|
|
|
|
// Verify battery optimization flag
|
|
assert_eq!(
|
|
capabilities.optimization_flags.get("battery_optimization"),
|
|
Some(&"true".to_string())
|
|
);
|
|
|
|
// Verify parallel capability flag
|
|
assert_eq!(
|
|
capabilities.optimization_flags.get("parallel_capable"),
|
|
Some(&"true".to_string())
|
|
);
|
|
}
|
|
|
|
#[test]
|
|
fn test_platform_detection_apis() {
|
|
// Test SIMD detection
|
|
let simd_support = EdgeCapabilityDetector::detect_simd_support();
|
|
assert!(matches!(
|
|
simd_support,
|
|
SIMDClass::NEON
|
|
| SIMDClass::AVX
|
|
| SIMDClass::RVV
|
|
| SIMDClass::WASM_SIMD
|
|
| SIMDClass::None
|
|
));
|
|
|
|
// Test power budget detection
|
|
let power_budget = EdgeCapabilityDetector::detect_power_budget();
|
|
assert!(matches!(
|
|
power_budget,
|
|
PowerClass::Unlimited
|
|
| PowerClass::HighBattery
|
|
| PowerClass::StandardBattery
|
|
| PowerClass::LowPower
|
|
| PowerClass::UltraLowPower
|
|
));
|
|
|
|
// Test network class detection
|
|
let network_class = EdgeCapabilityDetector::detect_network_class();
|
|
assert!(matches!(
|
|
network_class,
|
|
NetworkClass::HighSpeed
|
|
| NetworkClass::WiFi
|
|
| NetworkClass::Cellular
|
|
| NetworkClass::LowBandwidth
|
|
| NetworkClass::Offline
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn test_compute_units_detection() {
|
|
let compute_units = EdgeCapabilityDetector::detect_compute_units();
|
|
|
|
// Should detect at least 1 compute unit
|
|
assert!(compute_units > 0);
|
|
|
|
// On systems with std, should use available_parallelism
|
|
#[cfg(feature = "std")]
|
|
assert!(compute_units >= 1);
|
|
|
|
// On no_std systems, should default to 1
|
|
#[cfg(not(feature = "std"))]
|
|
assert_eq!(compute_units, 1);
|
|
}
|
|
|
|
#[test]
|
|
fn test_memory_detection() {
|
|
let memory_mb = EdgeCapabilityDetector::detect_memory_mb();
|
|
|
|
// Should detect reasonable memory amount
|
|
assert!(memory_mb > 0);
|
|
|
|
// Platform-specific minimum expectations
|
|
#[cfg(target_arch = "wasm32")]
|
|
assert!(memory_mb >= 512); // At least 512MB for WASM
|
|
|
|
#[cfg(any(target_arch = "arm", target_arch = "aarch64"))]
|
|
assert!(memory_mb >= 256); // At least 256MB for ARM
|
|
|
|
#[cfg(target_arch = "riscv64")]
|
|
assert!(memory_mb >= 128); // At least 128MB for RISC-V
|
|
}
|
|
|
|
#[test]
|
|
fn test_comprehensive_capability_profiling() {
|
|
let capabilities = EdgeCapabilityDetector::detect_edge_capabilities().unwrap();
|
|
|
|
// Verify all components were profiled
|
|
assert!(capabilities.compute_units > 0);
|
|
assert!(capabilities.memory_mb > 0);
|
|
assert!(matches!(
|
|
capabilities.simd_support,
|
|
SIMDClass::NEON
|
|
| SIMDClass::AVX
|
|
| SIMDClass::RVV
|
|
| SIMDClass::WASM_SIMD
|
|
| SIMDClass::None
|
|
));
|
|
assert!(matches!(
|
|
capabilities.power_budget,
|
|
PowerClass::Unlimited
|
|
| PowerClass::HighBattery
|
|
| PowerClass::StandardBattery
|
|
| PowerClass::LowPower
|
|
| PowerClass::UltraLowPower
|
|
));
|
|
assert!(matches!(
|
|
capabilities.network,
|
|
NetworkClass::HighSpeed
|
|
| NetworkClass::WiFi
|
|
| NetworkClass::Cellular
|
|
| NetworkClass::LowBandwidth
|
|
| NetworkClass::Offline
|
|
));
|
|
assert!(matches!(
|
|
capabilities.edge_class,
|
|
EdgeClass::HighEnd | EdgeClass::Mid | EdgeClass::Low | EdgeClass::IoT
|
|
));
|
|
|
|
// Check that optimization flags contain expected architecture info
|
|
assert!(capabilities.optimization_flags.contains_key("cpu_arch"));
|
|
assert!(capabilities.optimization_flags.contains_key("gemm_gflops"));
|
|
assert!(
|
|
capabilities
|
|
.optimization_flags
|
|
.contains_key("memory_bandwidth_gbps")
|
|
);
|
|
assert!(capabilities.optimization_flags.contains_key("l1_cache_kb"));
|
|
assert!(capabilities.optimization_flags.contains_key("l2_cache_kb"));
|
|
assert!(capabilities.optimization_flags.contains_key("l3_cache_kb"));
|
|
}
|
|
|
|
#[test]
|
|
fn test_edge_class_ordering_and_structures() {
|
|
// Test that edge classes have logical ordering for comparison
|
|
assert!(EdgeClass::HighEnd as u8 < EdgeClass::Mid as u8);
|
|
assert!(EdgeClass::Mid as u8 < EdgeClass::Low as u8);
|
|
assert!(EdgeClass::Low as u8 < EdgeClass::IoT as u8);
|
|
|
|
// Test structure validation
|
|
let cache_info = CacheInfo {
|
|
l1_cache_kb: 32,
|
|
l2_cache_kb: 256,
|
|
l3_cache_kb: 2048,
|
|
};
|
|
assert!(cache_info.l1_cache_kb > 0 && cache_info.l2_cache_kb > cache_info.l1_cache_kb);
|
|
|
|
let gpu_info = GpuInfo {
|
|
vendor: "Mali".to_string(),
|
|
memory_mb: 1024,
|
|
};
|
|
assert!(!gpu_info.vendor.is_empty() && gpu_info.memory_mb > 0);
|
|
|
|
let battery_info = BatteryInfo {
|
|
level: 80,
|
|
charging: false,
|
|
};
|
|
assert!(battery_info.level <= 100);
|
|
}
|
|
}
|