use serde::{Deserialize, Serialize};
use std::time::Instant;
use torsh_core::{Result as TorshResult, TorshError};
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum PlatformArch {
X86_64,
ARM64,
RISCV64,
WASM32,
WASM64,
Unknown,
}
impl PlatformArch {
pub fn detect() -> Self {
#[cfg(target_arch = "x86_64")]
return Self::X86_64;
#[cfg(target_arch = "aarch64")]
return Self::ARM64;
#[cfg(target_arch = "riscv64")]
return Self::RISCV64;
#[cfg(all(target_arch = "wasm32", not(target_pointer_width = "64")))]
return Self::WASM32;
#[cfg(all(target_arch = "wasm32", target_pointer_width = "64"))]
return Self::WASM64;
#[cfg(not(any(
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "riscv64",
target_arch = "wasm32"
)))]
return Self::Unknown;
}
pub fn is_arm(&self) -> bool {
matches!(self, Self::ARM64)
}
pub fn is_riscv(&self) -> bool {
matches!(self, Self::RISCV64)
}
pub fn is_wasm(&self) -> bool {
matches!(self, Self::WASM32 | Self::WASM64)
}
pub fn supports_hardware_counters(&self) -> bool {
matches!(self, Self::X86_64 | Self::ARM64 | Self::RISCV64)
}
}
impl std::fmt::Display for PlatformArch {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::X86_64 => write!(f, "x86_64"),
Self::ARM64 => write!(f, "ARM64 (AArch64)"),
Self::RISCV64 => write!(f, "RISC-V 64-bit"),
Self::WASM32 => write!(f, "WebAssembly 32-bit"),
Self::WASM64 => write!(f, "WebAssembly 64-bit"),
Self::Unknown => write!(f, "Unknown"),
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PlatformCapabilities {
pub arch: PlatformArch,
pub has_rdtsc: bool,
pub has_pmu: bool,
pub has_simd: bool,
pub simd_width: usize,
pub cache_line_size: usize,
pub supports_atomics: bool,
pub supports_threads: bool,
pub timer_resolution_ns: u64,
}
impl PlatformCapabilities {
pub fn detect() -> Self {
let arch = PlatformArch::detect();
let (has_rdtsc, has_pmu, has_simd, simd_width) = match arch {
PlatformArch::X86_64 => (true, true, true, 256), PlatformArch::ARM64 => (false, true, true, 128), PlatformArch::RISCV64 => (false, true, true, 128), PlatformArch::WASM32 | PlatformArch::WASM64 => (false, false, true, 128), PlatformArch::Unknown => (false, false, false, 0),
};
let cache_line_size = match arch {
PlatformArch::X86_64 => 64,
PlatformArch::ARM64 => 64,
PlatformArch::RISCV64 => 64,
PlatformArch::WASM32 | PlatformArch::WASM64 => 0, PlatformArch::Unknown => 64,
};
let supports_atomics = !arch.is_wasm(); let supports_threads = !arch.is_wasm();
let timer_resolution_ns = match arch {
PlatformArch::X86_64 => 1, PlatformArch::ARM64 => 10, PlatformArch::RISCV64 => 10, PlatformArch::WASM32 | PlatformArch::WASM64 => 1000, PlatformArch::Unknown => 1000,
};
Self {
arch,
has_rdtsc,
has_pmu,
has_simd,
simd_width,
cache_line_size,
supports_atomics,
supports_threads,
timer_resolution_ns,
}
}
}
pub struct CrossPlatformTimer {
start: Instant,
capabilities: PlatformCapabilities,
}
impl CrossPlatformTimer {
pub fn new() -> Self {
Self {
start: Instant::now(),
capabilities: PlatformCapabilities::detect(),
}
}
pub fn start(&mut self) {
self.start = Instant::now();
}
pub fn elapsed_us(&self) -> u64 {
self.start.elapsed().as_micros() as u64
}
pub fn elapsed_ns(&self) -> u64 {
self.start.elapsed().as_nanos() as u64
}
pub fn get_cycle_count(&self) -> Option<u64> {
#[cfg(target_arch = "x86_64")]
{
Some(unsafe { std::arch::x86_64::_rdtsc() })
}
#[cfg(target_arch = "aarch64")]
{
None
}
#[cfg(target_arch = "riscv64")]
{
None
}
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
{
None
}
#[cfg(not(any(
target_arch = "x86_64",
target_arch = "aarch64",
target_arch = "riscv64",
target_arch = "wasm32",
target_arch = "wasm64"
)))]
{
None
}
}
pub fn capabilities(&self) -> &PlatformCapabilities {
&self.capabilities
}
}
impl Default for CrossPlatformTimer {
fn default() -> Self {
Self::new()
}
}
#[cfg(target_arch = "aarch64")]
pub mod arm64 {
use super::*;
#[derive(Debug, Clone, Copy)]
pub enum ARM64Counter {
CycleCount,
InstructionCount,
CacheMisses,
BranchMisses,
L1DCacheAccess,
L1DCacheMiss,
L2CacheAccess,
L2CacheMiss,
}
pub struct NeonInfo {
pub available: bool,
pub register_width: usize,
pub num_registers: usize,
}
impl NeonInfo {
pub fn detect() -> Self {
Self {
available: true, register_width: 128,
num_registers: 32,
}
}
}
#[cfg(target_os = "macos")]
pub mod apple_silicon {
pub fn is_apple_silicon() -> bool {
cfg!(all(target_arch = "aarch64", target_os = "macos"))
}
pub fn performance_core_count() -> usize {
num_cpus::get() / 2
}
pub fn efficiency_core_count() -> usize {
num_cpus::get() / 2
}
}
}
#[cfg(target_arch = "riscv64")]
pub mod riscv {
use super::*;
#[derive(Debug, Clone, Copy)]
pub enum RISCVCounter {
CycleCount,
InstructionCount,
Time,
}
pub struct RVVInfo {
pub available: bool,
pub vlen: usize, }
impl RVVInfo {
pub fn detect() -> Self {
Self {
available: false, vlen: 0,
}
}
}
}
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
pub mod wasm {
use super::*;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WasmRuntime {
Browser,
Node,
Wasmtime,
Wasmer,
Unknown,
}
impl WasmRuntime {
pub fn detect() -> Self {
Self::Unknown
}
}
pub struct WasmSimdInfo {
pub available: bool,
pub simd128: bool,
}
impl WasmSimdInfo {
pub fn detect() -> Self {
Self {
available: true,
simd128: true, }
}
}
pub struct WasmMemoryProfiler {
initial_pages: usize,
max_pages: Option<usize>,
}
impl WasmMemoryProfiler {
pub fn new() -> Self {
Self {
initial_pages: 256, max_pages: Some(65536), }
}
pub fn current_memory_pages(&self) -> usize {
self.initial_pages
}
pub fn memory_bytes(&self) -> usize {
self.current_memory_pages() * 65536 }
}
impl Default for WasmMemoryProfiler {
fn default() -> Self {
Self::new()
}
}
}
pub struct CrossPlatformProfiler {
capabilities: PlatformCapabilities,
timer: CrossPlatformTimer,
}
impl CrossPlatformProfiler {
pub fn new() -> Self {
Self {
capabilities: PlatformCapabilities::detect(),
timer: CrossPlatformTimer::new(),
}
}
pub fn platform_info(&self) -> String {
format!(
"Platform: {}\n\
Hardware Counters: {}\n\
SIMD: {} (width: {} bits)\n\
Cache Line: {} bytes\n\
Atomics: {}\n\
Threads: {}\n\
Timer Resolution: {} ns",
self.capabilities.arch,
if self.capabilities.has_pmu {
"Yes"
} else {
"No"
},
if self.capabilities.has_simd {
"Yes"
} else {
"No"
},
self.capabilities.simd_width,
self.capabilities.cache_line_size,
if self.capabilities.supports_atomics {
"Yes"
} else {
"No"
},
if self.capabilities.supports_threads {
"Yes"
} else {
"No"
},
self.capabilities.timer_resolution_ns
)
}
pub fn start(&mut self) {
self.timer.start();
}
pub fn stop(&self) -> u64 {
self.timer.elapsed_us()
}
pub fn capabilities(&self) -> &PlatformCapabilities {
&self.capabilities
}
pub fn is_architecture(&self, arch: PlatformArch) -> bool {
self.capabilities.arch == arch
}
pub fn recommended_strategy(&self) -> ProfilingStrategy {
match self.capabilities.arch {
PlatformArch::X86_64 => ProfilingStrategy::HardwareCounters,
PlatformArch::ARM64 => ProfilingStrategy::Hybrid,
PlatformArch::RISCV64 => ProfilingStrategy::Sampling,
PlatformArch::WASM32 | PlatformArch::WASM64 => ProfilingStrategy::Lightweight,
PlatformArch::Unknown => ProfilingStrategy::Basic,
}
}
}
impl Default for CrossPlatformProfiler {
fn default() -> Self {
Self::new()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ProfilingStrategy {
HardwareCounters,
Hybrid,
Sampling,
Lightweight,
Basic,
}
impl std::fmt::Display for ProfilingStrategy {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::HardwareCounters => write!(f, "Hardware Counters"),
Self::Hybrid => write!(f, "Hybrid"),
Self::Sampling => write!(f, "Sampling"),
Self::Lightweight => write!(f, "Lightweight"),
Self::Basic => write!(f, "Basic"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_platform_detection() {
let arch = PlatformArch::detect();
println!("Detected architecture: {}", arch);
assert_ne!(arch, PlatformArch::Unknown);
}
#[test]
fn test_capabilities_detection() {
let caps = PlatformCapabilities::detect();
println!("Platform capabilities:");
println!(" Architecture: {}", caps.arch);
println!(" RDTSC: {}", caps.has_rdtsc);
println!(" PMU: {}", caps.has_pmu);
println!(" SIMD: {} (width: {})", caps.has_simd, caps.simd_width);
println!(" Cache line: {} bytes", caps.cache_line_size);
println!(" Atomics: {}", caps.supports_atomics);
println!(" Threads: {}", caps.supports_threads);
println!(" Timer resolution: {} ns", caps.timer_resolution_ns);
assert!(caps.cache_line_size > 0 || caps.arch.is_wasm());
}
#[test]
fn test_cross_platform_timer() {
let mut timer = CrossPlatformTimer::new();
timer.start();
std::thread::sleep(std::time::Duration::from_micros(100));
let elapsed = timer.elapsed_us();
println!("Elapsed time: {} μs", elapsed);
assert!(elapsed >= 100);
}
#[test]
fn test_cross_platform_profiler() {
let mut profiler = CrossPlatformProfiler::new();
println!("{}", profiler.platform_info());
profiler.start();
std::thread::sleep(std::time::Duration::from_micros(100));
let elapsed = profiler.stop();
println!("Profiled time: {} μs", elapsed);
assert!(elapsed >= 100);
let strategy = profiler.recommended_strategy();
println!("Recommended strategy: {}", strategy);
}
#[test]
fn test_architecture_checks() {
let profiler = CrossPlatformProfiler::new();
let arch = profiler.capabilities().arch;
assert_eq!(profiler.is_architecture(arch), true);
}
#[cfg(target_arch = "aarch64")]
#[test]
fn test_arm64_neon() {
let neon = arm64::NeonInfo::detect();
assert!(neon.available);
assert_eq!(neon.register_width, 128);
println!(
"NEON: {} registers of {} bits",
neon.num_registers, neon.register_width
);
}
#[cfg(all(target_arch = "aarch64", target_os = "macos"))]
#[test]
fn test_apple_silicon() {
if arm64::apple_silicon::is_apple_silicon() {
println!("Running on Apple Silicon");
println!(
"P-cores: {}",
arm64::apple_silicon::performance_core_count()
);
println!("E-cores: {}", arm64::apple_silicon::efficiency_core_count());
}
}
}