auto_allocator/lib.rs
1//! # Auto Allocator - Zero-Configuration Memory Optimization
2//!
3//! **Just add one line and get optimal memory performance automatically!**
4//!
5//! Auto-allocator automatically selects the best memory allocator for your platform and hardware,
6//! giving you significant performance improvements without any configuration or code changes.
7//!
8//! ## Why Auto Allocator?
9//!
10//! - **🚀 Instant Performance**: Up to 1.6x faster allocation in multi-threaded applications
11//! - **🔧 Zero Configuration**: Works perfectly out-of-the-box, no setup required
12//! - **🌍 Universal Compatibility**: Optimizes across all platforms - servers, desktop, mobile, embedded, WASM
13//! - **🧠 Platform Intelligence**: Automatically chooses the best allocator for each platform
14//! - **⚡ Production Ready**: Used safely in high-performance production environments
15//!
16//! ## Quick Start
17//!
18//! **Step 1:** Add to your `Cargo.toml`:
19//! ```toml
20//! [dependencies]
21//! auto-allocator = "*"
22//! ```
23//!
24//! **Step 2:** Add one line to your `main.rs`:
25//! ```rust,ignore
26//! use auto_allocator; // That's it! 🎉
27//!
28//! fn main() {
29//! // Your code automatically runs with optimal memory performance
30//! let data = vec![1, 2, 3, 4, 5];
31//! println!("Memory allocations are now optimized!");
32//! }
33//! ```
34//!
35//! **That's literally all you need!** Auto-allocator handles everything else automatically.
36//!
37//! ## What You Get
38//!
39//! - **Linux Servers**: mimalloc for superior multi-threaded performance
40//! - **Windows/macOS**: mimalloc for desktop application speed
41//! - **Android/iOS**: Platform-optimized system allocators (Scudo/libmalloc)
42//! - **Docker/Kubernetes**: Optimized for containerized deployments
43//! - **Embedded Systems**: Automatic embedded-alloc for all no_std platforms (RISC-V, ARM, AVR, MSP430, Xtensa, etc.)
44//! - **WASM**: Compatible allocation for web applications
45//!
46//! **Security Mode Available:**
47//! ```toml
48//! auto-allocator = { version = "*", features = ["secure"] }
49//! ```
50
51#![cfg_attr(target_os = "none", no_std)]
52
53// Conditional imports for std vs no_std
54#[cfg(not(target_os = "none"))]
55use log::info;
56#[cfg(not(target_os = "none"))]
57use once_cell::sync::Lazy;
58
59use core::alloc::{GlobalAlloc, Layout};
60use core::sync::atomic::{AtomicU8, Ordering};
61#[cfg(not(target_os = "none"))]
62use core::sync::atomic::AtomicBool;
63
64// Import std-specific modules conditionally
65#[cfg(not(target_os = "none"))]
66use std::alloc;
67
68// ========== Type Definitions ==========
69
70/// Memory allocator type enumeration
71///
72/// Represents all memory allocator types supported by auto-allocator.
73/// Selection priority: mimalloc > embedded > system
74///
75/// # Performance Characteristics
76///
77/// - [`AllocatorType::MimallocSecure`] - Microsoft-developed allocator with security hardening (10% overhead)
78/// - [`AllocatorType::Mimalloc`] - Microsoft-developed allocator, optimal multi-threaded performance
79/// - [`AllocatorType::EmbeddedHeap`] - Lightweight allocator for resource-constrained environments
80/// - [`AllocatorType::System`] - Operating system default allocator, maximum compatibility
81///
82/// # Automatic Selection Logic
83///
84/// 1. **Modern Linux**: mimalloc (if GCC 4.9+ and stdatomic.h available)
85/// 2. **Legacy Linux**: Compilation error with upgrade guidance
86/// 3. **Windows/macOS**: mimalloc (always available)
87/// 4. **Mobile/BSD**: System allocators (platform compliance)
88/// 5. **Embedded** (`target_os = "none"`): embedded-alloc (all no_std architectures)
89///
90/// # Example
91///
92/// ```rust
93/// use auto_allocator;
94///
95/// let info = auto_allocator::get_allocator_info();
96/// match info.allocator_type {
97/// auto_allocator::AllocatorType::Mimalloc => {
98/// println!("Using mimalloc - optimal performance");
99/// }
100/// auto_allocator::AllocatorType::System => {
101/// println!("Using system allocator - platform compliance");
102/// }
103/// _ => println!("Using other allocator"),
104/// }
105/// ```
106#[derive(Debug, Clone, Copy, PartialEq, Eq)]
107pub enum AllocatorType {
108
109 /// Security-hardened mimalloc allocator
110 ///
111 /// Microsoft-developed allocator with enhanced security features.
112 /// ~10% performance overhead for comprehensive heap protection.
113 /// Available when `secure` feature is enabled on compatible platforms.
114 MimallocSecure,
115
116 /// High-performance mimalloc allocator
117 ///
118 /// Microsoft-developed allocator optimized for multi-threaded workloads.
119 /// Automatically selected on modern systems with GCC 4.9+ and stdatomic.h.
120 Mimalloc,
121
122
123 /// Embedded systems allocator
124 ///
125 /// Lightweight allocator designed for resource-constrained environments.
126 /// Automatically selected on embedded architectures.
127 EmbeddedHeap,
128
129 /// System default allocator
130 ///
131 /// Operating system provided allocator, maximum compatibility.
132 /// Selected for debug builds, WASM, mobile, and platforms with optimized native allocators.
133 System,
134}
135
136/// Allocator information structure
137///
138/// Contains the currently selected allocator type, selection reason, and system information.
139/// Obtained through the [`get_allocator_info()`] function.
140///
141/// # Fields
142///
143/// - `allocator_type` - Currently used allocator type
144/// - `reason` - Detailed reason for allocator selection, including hardware information
145/// - `system_info` - System hardware and environment information
146///
147/// # Example
148///
149/// ```rust
150/// use auto_allocator;
151///
152/// let info = auto_allocator::get_allocator_info();
153/// println!("Allocator: {:?}", info.allocator_type);
154/// println!("Selection reason: {}", info.reason);
155/// println!("CPU cores: {}", info.system_info.cpu_cores);
156/// ```
157#[derive(Debug, Clone)]
158pub struct AllocatorInfo {
159 /// Currently used allocator type
160 pub allocator_type: AllocatorType,
161
162 /// Detailed reason for allocator selection
163 ///
164 /// Contains hardware detection results and selection logic explanation, for example:
165 /// "mimalloc selected by runtime hardware analysis (16 cores, 128GB total RAM)"
166 #[cfg(not(target_os = "none"))]
167 pub reason: String,
168 #[cfg(target_os = "none")]
169 pub reason: &'static str,
170
171 /// System hardware and environment information
172 pub system_info: SystemInfo,
173}
174
175/// System information structure
176///
177/// Contains runtime-detected system hardware and environment information,
178/// used for allocator selection decisions.
179///
180/// # Fields
181///
182/// - `os_type` - Operating system type (linux, macos, windows, etc.)
183/// - `cpu_cores` - CPU core count (including hyperthreaded cores)
184/// - `total_memory_bytes` - Total memory in bytes
185/// - `is_debug` - Whether this is a Debug build
186/// - `is_wasm` - Whether this is a WASM environment
187/// - `target_arch` - Target architecture (x86_64, aarch64, etc.)
188///
189/// # Example
190///
191/// ```rust
192/// use auto_allocator;
193///
194/// let info = auto_allocator::get_allocator_info();
195/// let sys = &info.system_info;
196///
197/// println!("Operating system: {}", sys.os_type);
198/// println!("CPU cores: {}", sys.cpu_cores);
199/// println!("Total memory: {}", auto_allocator::format_memory_size(sys.total_memory_bytes));
200/// ```
201#[derive(Debug, Clone)]
202pub struct SystemInfo {
203 /// Operating system type
204 ///
205 /// Examples: "linux", "macos", "windows", "unknown"
206 #[cfg(not(target_os = "none"))]
207 pub os_type: String,
208 #[cfg(target_os = "none")]
209 pub os_type: &'static str,
210
211 /// CPU core count
212 ///
213 /// Detected via `std::thread::available_parallelism()`, includes hyperthreaded core count
214 pub cpu_cores: usize,
215
216 /// Total memory in bytes
217 ///
218 /// System total physical memory, used for hardware specification assessment.
219 /// Use [`format_memory_size()`] to format as human-readable string.
220 pub total_memory_bytes: u64,
221
222 /// Whether this is a Debug build
223 ///
224 /// Debug builds automatically select system allocator for faster compilation
225 pub is_debug: bool,
226
227 /// Whether this is a WASM environment
228 ///
229 /// WASM environments automatically select system allocator for compatibility
230 pub is_wasm: bool,
231
232 /// Target architecture
233 ///
234 /// Examples: "x86_64", "aarch64", "riscv32", "wasm32"
235 #[cfg(not(target_os = "none"))]
236 pub target_arch: String,
237 #[cfg(target_os = "none")]
238 pub target_arch: &'static str,
239}
240
241// ========== Memory Formatting Utilities ==========
242
243/// High-performance memory size formatting function
244///
245/// Converts byte count to human-readable memory size string, automatically selecting appropriate units.
246/// Uses bit shift operations for performance optimization, supports memory sizes from bytes to PB level.
247///
248/// # Arguments
249///
250/// - `bytes` - The number of bytes to format
251///
252/// # Returns
253///
254/// Returns formatted string, for example:
255/// - `1024` → `"1KB"`
256/// - `1536` → `"1.5KB"`
257/// - `1073741824` → `"1GB"`
258///
259/// # Supported Units
260///
261/// - **B** - Bytes (< 1024)
262/// - **KB** - Kilobytes (1024 B)
263/// - **MB** - Megabytes (1024 KB)
264/// - **GB** - Gigabytes (1024 MB)
265/// - **TB** - Terabytes (1024 GB)
266/// - **PB** - Petabytes (1024 TB)
267///
268/// # Performance Features
269///
270/// - Uses bit shift operations instead of division for performance optimization
271/// - Hardware-optimized leading zero count instructions
272/// - Retains only 1 decimal place for improved performance
273/// - Zero-copy string construction
274///
275/// # Examples
276///
277/// ```rust
278/// use auto_allocator;
279///
280/// // Basic usage
281/// assert_eq!(auto_allocator::format_memory_size(0), "0B");
282/// assert_eq!(auto_allocator::format_memory_size(1024), "1KB");
283/// assert_eq!(auto_allocator::format_memory_size(1536), "1.5KB");
284/// assert_eq!(auto_allocator::format_memory_size(1048576), "1MB");
285/// assert_eq!(auto_allocator::format_memory_size(1073741824), "1GB");
286///
287/// // Use in combination with system information
288/// let info = auto_allocator::get_allocator_info();
289/// let memory_str = auto_allocator::format_memory_size(info.system_info.total_memory_bytes);
290/// println!("Total system memory: {}", memory_str);
291///
292/// // Display memory usage in application
293/// fn display_memory_usage() {
294/// let info = auto_allocator::get_allocator_info();
295/// println!("Memory information:");
296/// println!(" Total memory: {}", auto_allocator::format_memory_size(info.system_info.total_memory_bytes));
297/// }
298/// ```
299///
300/// # Precision Notes
301///
302/// For performance considerations, decimal places are limited to 1 digit. For scenarios
303/// requiring higher precision, it is recommended to calculate directly using byte counts.
304#[cfg(not(target_os = "none"))]
305pub fn format_memory_size(bytes: u64) -> String {
306 use std::format;
307
308 if bytes == 0 {
309 return "0B".to_string();
310 }
311
312 // Use bit shift calculations to avoid division operations for performance improvement
313 // Each unit has a 1024x relationship, i.e., 2^10
314 const UNITS: &[&str] = &["B", "KB", "MB", "GB", "TB", "PB"];
315
316 // Use leading zero count to quickly determine appropriate unit level
317 // leading_zeros() is a hardware-optimized instruction
318 let unit_index = if bytes >= (1u64 << 50) {
319 5
320 }
321 // >= 1PB
322 else if bytes >= (1u64 << 40) {
323 4
324 }
325 // >= 1TB
326 else if bytes >= (1u64 << 30) {
327 3
328 }
329 // >= 1GB
330 else if bytes >= (1u64 << 20) {
331 2
332 }
333 // >= 1MB
334 else if bytes >= (1u64 << 10) {
335 1
336 }
337 // >= 1KB
338 else {
339 0
340 }; // < 1KB
341
342 if unit_index == 0 {
343 format!("{}B", bytes)
344 } else {
345 let shift = unit_index * 10; // Each unit is 2^10
346 let value = bytes >> shift;
347 let remainder = bytes & ((1u64 << shift) - 1);
348
349 // Calculate decimal part (retain only 1 decimal place for performance)
350 if remainder == 0 {
351 format!("{}{}", value, UNITS[unit_index])
352 } else {
353 let fraction = (remainder * 10) >> shift;
354 if fraction == 0 {
355 format!("{}{}", value, UNITS[unit_index])
356 } else {
357 format!("{}.{}{}", value, fraction, UNITS[unit_index])
358 }
359 }
360 }
361}
362
363/// Simplified memory size formatting for no_std environments
364#[cfg(target_os = "none")]
365pub fn format_memory_size(bytes: u64) -> &'static str {
366 // For embedded systems, use predefined size categories
367 if bytes == 0 {
368 "0B"
369 } else if bytes < 1024 {
370 "<1KB"
371 } else if bytes < (1024 * 1024) {
372 "~KB"
373 } else if bytes < (1024 * 1024 * 1024) {
374 "~MB"
375 } else {
376 "~GB"
377 }
378}
379
380// ========== Platform Detection ==========
381
382/// Checks if the target is an embedded platform requiring specialized allocation
383///
384/// Uses `target_os = "none"` as the primary indicator of embedded/no_std environments.
385/// This approach covers all current and future embedded targets automatically,
386/// including architectures like RISC-V, ARM, AVR, MSP430, Xtensa, LoongArch, etc.
387const fn is_embedded_target() -> bool {
388 cfg!(target_os = "none")
389}
390
391/// Checks if mimalloc can be used on this platform
392const fn can_use_mimalloc() -> bool {
393 cfg!(all(
394 feature = "_mimalloc",
395 any(target_os = "windows", target_os = "macos", target_os = "linux"),
396 not(target_arch = "wasm32"),
397 not(debug_assertions)
398 ))
399}
400
401/// Checks if secure mimalloc can be used on this platform
402const fn can_use_mimalloc_secure() -> bool {
403 cfg!(all(
404 feature = "_mimalloc_secure",
405 any(target_os = "windows", target_os = "macos", target_os = "linux"),
406 not(target_arch = "wasm32"),
407 not(debug_assertions)
408 ))
409}
410
411
412
413// ========== Runtime Allocator Selection ==========
414
415// Global state for allocator selection and logging
416// ID mapping: 0=uninitialized, 1=system, 2=mimalloc, 3=jemalloc, 4=embedded, 5=mimalloc-secure
417static RUNTIME_ALLOCATOR_ID: AtomicU8 = AtomicU8::new(0);
418#[cfg(not(target_os = "none"))]
419static ALLOCATOR_LOGGED: AtomicBool = AtomicBool::new(false);
420#[cfg(not(target_os = "none"))]
421static LOG_FLUSHED: AtomicBool = AtomicBool::new(false);
422
423/// Returns allocator ID for platforms with compile-time determinable choices
424///
425/// Returns `None` for platforms requiring runtime hardware detection (desktop systems).
426/// This optimization avoids unnecessary runtime checks for 90% of platforms.
427const fn get_compile_time_allocator() -> Option<u8> {
428 if is_embedded_target() {
429 return Some(4); // embedded-alloc
430 }
431
432 if cfg!(target_arch = "wasm32") {
433 return Some(1); // system
434 }
435
436 if cfg!(debug_assertions) {
437 return Some(1); // system (debug builds)
438 }
439
440 // Platforms with superior native allocators
441 if cfg!(target_os = "android") {
442 return Some(1); // Scudo
443 }
444
445 if cfg!(target_os = "ios") {
446 return Some(1); // libmalloc
447 }
448
449 if cfg!(any(target_os = "freebsd", target_os = "netbsd", target_os = "openbsd")) {
450 return Some(1); // native jemalloc/security-hardened
451 }
452
453 if cfg!(any(target_os = "solaris", target_os = "illumos")) {
454 return Some(1); // libumem
455 }
456
457 None // High-performance platforms need runtime detection
458}
459
460/// Selects allocator using compile-time rules and runtime hardware detection
461fn select_allocator_by_hardware() -> u8 {
462 if let Some(allocator_id) = get_compile_time_allocator() {
463 return allocator_id;
464 }
465
466 // Only high-performance platforms reach here - need CPU core detection
467 // Use zero-allocation CPU detection to avoid infinite recursion
468 let cpu_cores = get_cpu_cores_safe();
469
470 // Multi-core systems: prefer mimalloc (secure > regular > system)
471 if cpu_cores >= 2 && can_use_mimalloc_secure() {
472 return 5; // mimalloc-secure
473 }
474
475 // Check if mimalloc is available
476 // Since build script ensures compatibility, mimalloc is available if feature is enabled
477 if cpu_cores >= 2 && can_use_mimalloc() {
478 return 2; // mimalloc
479 }
480
481 1 // system (single-core or all high-performance allocators unavailable)
482}
483
484/// Get CPU core count without allocating memory (to avoid infinite recursion)
485fn get_cpu_cores_safe() -> usize {
486 #[cfg(unix)]
487 {
488 // Use direct libc calls to avoid std allocation
489 unsafe {
490 let cores = libc::sysconf(libc::_SC_NPROCESSORS_ONLN);
491 if cores > 0 {
492 cores as usize
493 } else {
494 1
495 }
496 }
497 }
498
499 #[cfg(windows)]
500 {
501 // Windows: Use direct WinAPI to avoid std allocation
502 use winapi::um::sysinfoapi::{GetSystemInfo, SYSTEM_INFO};
503 unsafe {
504 let mut sysinfo: SYSTEM_INFO = std::mem::zeroed();
505 GetSystemInfo(&mut sysinfo);
506 sysinfo.dwNumberOfProcessors as usize
507 }
508 }
509
510 #[cfg(not(any(unix, windows)))]
511 {
512 // Fallback: assume multi-core for unknown platforms
513 4
514 }
515}
516
517// ========== Embedded Heap Configuration ==========
518
519// Embedded heap configuration for all no_std targets
520#[cfg(target_os = "none")]
521mod embedded_heap_config {
522 use embedded_alloc::Heap;
523 #[cfg(not(target_os = "none"))]
524 use once_cell::sync::Lazy;
525
526 // Architecture-specific heap sizes based on typical available memory
527 // These are conservative defaults that work well for most embedded applications
528 // Users can override by defining custom heap sizes in their own code
529
530 #[cfg(target_arch = "avr")]
531 pub const HEAP_SIZE: usize = 512; // AVR (Arduino Uno): 2KB total, use 512B heap (25%)
532
533 #[cfg(target_arch = "msp430")]
534 pub const HEAP_SIZE: usize = 256; // MSP430: 1KB total, use 256B heap (25%)
535
536 #[cfg(target_arch = "riscv32")]
537 pub const HEAP_SIZE: usize = 2048; // RISC-V 32-bit: typically 32KB+, use 2KB heap (6%)
538
539 #[cfg(target_arch = "riscv64")]
540 pub const HEAP_SIZE: usize = 4096; // RISC-V 64-bit: typically 128KB+, use 4KB heap (3%)
541
542 #[cfg(target_arch = "xtensa")]
543 pub const HEAP_SIZE: usize = 4096; // Xtensa (ESP32): 256KB+, use 4KB heap (1.5%)
544
545 #[cfg(target_arch = "arm")]
546 pub const HEAP_SIZE: usize = 1024; // ARM Cortex-M: typically 16KB+, use 1KB heap (6%)
547
548 // Default heap size for other embedded architectures (LoongArch, Hexagon, BPF, SPARC, etc.)
549 #[cfg(not(any(
550 target_arch = "avr",
551 target_arch = "msp430",
552 target_arch = "riscv32",
553 target_arch = "riscv64",
554 target_arch = "xtensa",
555 target_arch = "arm"
556 )))]
557 pub const HEAP_SIZE: usize = 2048; // Conservative default for unknown architectures
558
559 // Static memory pool for embedded heap
560 // This is a conservative allocation that should work on most embedded systems
561 pub static mut HEAP_MEMORY: [u8; HEAP_SIZE] = [0; HEAP_SIZE];
562
563 // Singleton heap instance - different implementations for std vs no_std
564 #[cfg(not(target_os = "none"))]
565 pub static EMBEDDED_HEAP: Lazy<Heap> = Lazy::new(|| unsafe { Heap::new(&mut HEAP_MEMORY[..]) });
566
567 #[cfg(target_os = "none")]
568 static mut EMBEDDED_HEAP_INSTANCE: Option<Heap> = None;
569
570 /// Gets the embedded heap instance for no_std environments
571 ///
572 /// This function provides access to the global embedded heap used in no_std
573 /// environments. The heap is lazily initialized on first access with
574 /// architecture-appropriate size defaults.
575 ///
576 /// # Returns
577 ///
578 /// A reference to the static embedded heap instance
579 ///
580 /// # Safety
581 ///
582 /// This function is only available in no_std environments (`target_os = "none"`).
583 /// The heap initialization is done safely using static guarantees.
584 #[cfg(target_os = "none")]
585 pub fn get_embedded_heap() -> &'static Heap {
586 unsafe {
587 if EMBEDDED_HEAP_INSTANCE.is_none() {
588 let heap = Heap::empty();
589 heap.init(HEAP_MEMORY.as_mut_ptr() as usize, HEAP_SIZE);
590 EMBEDDED_HEAP_INSTANCE = Some(heap);
591 }
592 EMBEDDED_HEAP_INSTANCE.as_ref().unwrap()
593 }
594 }
595}
596
597// ========== Safe Runtime Allocator Implementation ==========
598
599pub struct RuntimeAllocator;
600
601impl RuntimeAllocator {
602 #[inline]
603 fn get_allocator_id() -> u8 {
604 let current_id = RUNTIME_ALLOCATOR_ID.load(Ordering::Acquire);
605
606 if unlikely(current_id == 0) {
607 // First call, perform hardware detection and selection
608 let selected_id = select_allocator_by_hardware();
609 RUNTIME_ALLOCATOR_ID.store(selected_id, Ordering::Release);
610
611 // Record selection information (ensure only logged once)
612 Self::log_allocator_selection(selected_id);
613
614 selected_id
615 } else {
616 current_id
617 }
618 }
619
620 #[cold]
621 #[cfg(not(target_os = "none"))]
622 fn log_allocator_selection(allocator_id: u8) {
623 if ALLOCATOR_LOGGED
624 .compare_exchange(false, true, Ordering::AcqRel, Ordering::Acquire)
625 .is_ok()
626 {
627 let (name, reason) = Self::get_allocator_log_info(allocator_id);
628 record_allocator_selection(name, &reason);
629 }
630 }
631
632 #[cold]
633 #[cfg(target_os = "none")]
634 fn log_allocator_selection(_allocator_id: u8) {
635 // No logging in no_std environments
636 }
637
638 /// Get logging information based on allocator ID and compile-time platform detection
639 #[cfg(not(target_os = "none"))]
640 fn get_allocator_log_info(allocator_id: u8) -> (&'static str, String) {
641 match allocator_id {
642 5 => {
643 let system_info = collect_system_info();
644 ("mimalloc-secure", format!(
645 "security-hardened choice - runtime detected ({} cores, {} total RAM)",
646 system_info.cpu_cores,
647 format_memory_size(system_info.total_memory_bytes)
648 ))
649 },
650 2 => {
651 let system_info = collect_system_info();
652 ("mimalloc", format!(
653 "optimal performance choice - runtime detected ({} cores, {} total RAM)",
654 system_info.cpu_cores,
655 format_memory_size(system_info.total_memory_bytes)
656 ))
657 },
658 4 => {
659 let system_info = collect_system_info();
660 ("embedded-alloc", format!(
661 "embedded platform - compile-time selected ({} total RAM)",
662 format_memory_size(system_info.total_memory_bytes)
663 ))
664 },
665 _ => {
666 // System allocator - determine reason based on compile-time platform detection
667 if cfg!(debug_assertions) {
668 let system_info = collect_system_info();
669 ("system", format!(
670 "debug build - compile-time selected ({} cores, {} total RAM)",
671 system_info.cpu_cores,
672 format_memory_size(system_info.total_memory_bytes)
673 ))
674 } else if cfg!(target_arch = "wasm32") {
675 let system_info = collect_system_info();
676 ("system", format!(
677 "WASM environment - compile-time selected ({} total RAM)",
678 format_memory_size(system_info.total_memory_bytes)
679 ))
680 } else if cfg!(target_os = "android") {
681 let system_info = collect_system_info();
682 ("system", format!(
683 "Android Scudo allocator - compile-time selected (security-first policy) ({} cores, {} total RAM)",
684 system_info.cpu_cores,
685 format_memory_size(system_info.total_memory_bytes)
686 ))
687 } else if cfg!(target_os = "ios") {
688 let system_info = collect_system_info();
689 ("system", format!(
690 "iOS libmalloc allocator - compile-time selected (Apple optimized) ({} cores, {} total RAM)",
691 system_info.cpu_cores,
692 format_memory_size(system_info.total_memory_bytes)
693 ))
694 } else if cfg!(any(target_os = "freebsd", target_os = "netbsd")) {
695 let system_info = collect_system_info();
696 ("system", format!(
697 "BSD native jemalloc - compile-time selected (platform optimized) ({} cores, {} total RAM)",
698 system_info.cpu_cores,
699 format_memory_size(system_info.total_memory_bytes)
700 ))
701 } else if cfg!(target_os = "openbsd") {
702 let system_info = collect_system_info();
703 ("system", format!(
704 "OpenBSD security-hardened allocator - compile-time selected ({} cores, {} total RAM)",
705 system_info.cpu_cores,
706 format_memory_size(system_info.total_memory_bytes)
707 ))
708 } else if cfg!(any(target_os = "solaris", target_os = "illumos")) {
709 let system_info = collect_system_info();
710 ("system", format!(
711 "Solaris libumem allocator - compile-time selected (enterprise grade) ({} cores, {} total RAM)",
712 system_info.cpu_cores,
713 format_memory_size(system_info.total_memory_bytes)
714 ))
715 } else {
716 // High-performance platforms that fell back to system (single-core or mimalloc unavailable)
717 let system_info = collect_system_info();
718 ("system", format!(
719 "runtime fallback - single-core or mimalloc unavailable ({} cores, {} total RAM)",
720 system_info.cpu_cores,
721 format_memory_size(system_info.total_memory_bytes)
722 ))
723 }
724 },
725 }
726 }
727}
728
729// Branch prediction optimization
730#[inline(always)]
731fn unlikely(b: bool) -> bool {
732 #[cold]
733 fn cold() {}
734 if b {
735 cold();
736 }
737 b
738}
739
740// ========== Global Allocator Implementation - Platform-specific VTable handling ==========
741
742unsafe impl GlobalAlloc for RuntimeAllocator {
743 #[inline]
744 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
745 match Self::get_allocator_id() {
746
747 // mimalloc-secure - security-hardened allocator with 10% performance overhead
748 #[cfg(all(
749 feature = "_mimalloc_secure",
750 not(target_arch = "wasm32"),
751 not(debug_assertions),
752 not(target_os = "none")
753 ))]
754 5 => {
755 use mimalloc::MiMalloc;
756 MiMalloc.alloc(layout)
757 }
758
759 // mimalloc - high-performance allocator with compiler compatibility detection
760 #[cfg(all(
761 feature = "_mimalloc",
762 not(target_arch = "wasm32"),
763 not(debug_assertions),
764 not(target_os = "none")
765 ))]
766 2 => {
767 use mimalloc::MiMalloc;
768 MiMalloc.alloc(layout)
769 }
770
771 // embedded-alloc - for all no_std embedded platforms
772 #[cfg(all(
773 feature = "_embedded",
774 target_os = "none"
775 ))]
776 4 => {
777 // Use embedded-alloc for all no_std targets
778 #[cfg(not(target_os = "none"))]
779 {
780 embedded_heap_config::EMBEDDED_HEAP.alloc(layout)
781 }
782 #[cfg(target_os = "none")]
783 {
784 embedded_heap_config::get_embedded_heap().alloc(layout)
785 }
786 }
787
788 // System allocator - default fallback
789 #[cfg(not(target_os = "none"))]
790 _ => alloc::System.alloc(layout),
791
792 #[cfg(target_os = "none")]
793 _ => core::ptr::null_mut(),
794 }
795 }
796
797 #[inline]
798 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
799 match Self::get_allocator_id() {
800
801 // mimalloc-secure - security-hardened allocator
802 #[cfg(all(
803 feature = "_mimalloc_secure",
804 not(target_arch = "wasm32"),
805 not(debug_assertions),
806 not(target_os = "none")
807 ))]
808 5 => {
809 use mimalloc::MiMalloc;
810 MiMalloc.dealloc(ptr, layout)
811 }
812
813 // mimalloc - high-performance allocator with compiler compatibility detection
814 #[cfg(all(
815 feature = "_mimalloc",
816 not(target_arch = "wasm32"),
817 not(debug_assertions),
818 not(target_os = "none")
819 ))]
820 2 => {
821 use mimalloc::MiMalloc;
822 MiMalloc.dealloc(ptr, layout)
823 }
824
825 #[cfg(all(
826 feature = "_embedded",
827 target_os = "none"
828 ))]
829 4 => {
830 // Use embedded-alloc for all no_std targets
831 #[cfg(not(target_os = "none"))]
832 {
833 embedded_heap_config::EMBEDDED_HEAP.dealloc(ptr, layout)
834 }
835 #[cfg(target_os = "none")]
836 {
837 embedded_heap_config::get_embedded_heap().dealloc(ptr, layout)
838 }
839 }
840
841 #[cfg(not(target_os = "none"))]
842 _ => alloc::System.dealloc(ptr, layout),
843
844 #[cfg(target_os = "none")]
845 _ => {},
846 }
847 }
848}
849
850#[global_allocator]
851static GLOBAL: RuntimeAllocator = RuntimeAllocator;
852
853// ========== Logging System ==========
854
855#[cfg(not(target_os = "none"))]
856static PENDING_LOG_MESSAGE: Lazy<std::sync::Mutex<Option<String>>> =
857 Lazy::new(|| std::sync::Mutex::new(None));
858
859/// Records allocator selection using a dual logging strategy
860///
861/// Immediately outputs to stderr (safe during global allocator init) and
862/// saves for later output through the logging framework when available.
863#[cfg(not(target_os = "none"))]
864fn record_allocator_selection(allocator_name: &str, reason: &str) {
865 let message = format!("Auto-allocator: {} selected - {}", allocator_name, reason);
866
867 // Immediate output to stderr (only safe method in global allocator)
868 #[cfg(unix)]
869 {
870 let stderr_message = format!("[INFO] {}\n", message);
871 unsafe {
872 libc::write(
873 2,
874 stderr_message.as_ptr() as *const libc::c_void,
875 stderr_message.len(),
876 );
877 }
878 }
879
880 // Save message, output later through logging framework
881 if let Ok(mut pending) = PENDING_LOG_MESSAGE.lock() {
882 *pending = Some(message);
883 }
884}
885
886/// Attempts to flush pending log message to the logging framework
887#[cfg(not(target_os = "none"))]
888fn try_flush_pending_log() {
889 if !LOG_FLUSHED.load(Ordering::Relaxed) {
890 if let Ok(mut pending) = PENDING_LOG_MESSAGE.lock() {
891 if let Some(message) = pending.take() {
892 let _ = std::panic::catch_unwind(|| {
893 info!("{}", message);
894 });
895 LOG_FLUSHED.store(true, Ordering::Relaxed);
896 }
897 }
898 }
899}
900
901/// Intelligently flushes logs when the logging framework becomes available
902#[cfg(not(target_os = "none"))]
903fn smart_try_flush_log() {
904 // If already output, no need to try again
905 if LOG_FLUSHED.load(Ordering::Relaxed) {
906 return;
907 }
908
909 // Try to output log
910 try_flush_pending_log();
911
912 // If still not successful, logging framework is not yet initialized
913 // Will continue trying on next call
914}
915
916// ========== System Information Collection ==========
917
918#[cfg(not(target_os = "none"))]
919fn collect_system_info() -> SystemInfo {
920 let total_memory = get_total_memory_safe();
921 SystemInfo {
922 os_type: std::env::consts::OS.to_string(),
923 cpu_cores: std::thread::available_parallelism()
924 .map(|n| n.get())
925 .unwrap_or(1),
926 total_memory_bytes: total_memory,
927 is_debug: cfg!(debug_assertions),
928 is_wasm: cfg!(target_arch = "wasm32"),
929 target_arch: std::env::consts::ARCH.to_string(),
930 }
931}
932
933/// Simplified system info collection for no_std environments
934#[cfg(target_os = "none")]
935fn collect_system_info() -> SystemInfo {
936 let total_memory = get_total_memory_safe();
937 SystemInfo {
938 os_type: "embedded",
939 cpu_cores: 1, // Assume single core for embedded
940 total_memory_bytes: total_memory,
941 is_debug: cfg!(debug_assertions),
942 is_wasm: false,
943 target_arch: {
944 #[cfg(target_arch = "riscv32")]
945 { "riscv32" }
946 #[cfg(target_arch = "riscv64")]
947 { "riscv64" }
948 #[cfg(target_arch = "arm")]
949 { "arm" }
950 #[cfg(target_arch = "avr")]
951 { "avr" }
952 #[cfg(target_arch = "msp430")]
953 { "msp430" }
954 #[cfg(target_arch = "xtensa")]
955 { "xtensa" }
956 #[cfg(not(any(
957 target_arch = "riscv32",
958 target_arch = "riscv64",
959 target_arch = "arm",
960 target_arch = "avr",
961 target_arch = "msp430",
962 target_arch = "xtensa"
963 )))]
964 { "unknown" }
965 },
966 }
967}
968
969/// Detects total system memory without allocating during global allocator initialization
970///
971/// Uses platform-specific APIs for servers/desktop systems and conservative defaults for embedded platforms.
972/// Critical: This function must not allocate memory as it's called during global allocator setup.
973#[allow(unreachable_code)]
974fn get_total_memory_safe() -> u64 {
975 #[cfg(target_arch = "wasm32")]
976 {
977 // WASM can dynamically detect memory through core::arch::wasm32
978 use core::arch::wasm32;
979
980 // Get current memory pages, each page is 64KB
981 let pages = wasm32::memory_size(0); // Memory index 0 is default memory
982 let total_bytes = (pages as u64) * 65536;
983
984 return total_bytes;
985 }
986
987 #[cfg(target_os = "macos")]
988 {
989 // macOS: use sysctl(HW_MEMSIZE)
990 unsafe {
991 let mut total_size: u64 = 0;
992 let mut mib = [libc::CTL_HW, libc::HW_MEMSIZE];
993 let mut len = std::mem::size_of::<u64>();
994
995 if libc::sysctl(
996 mib.as_mut_ptr(),
997 2,
998 &mut total_size as *mut _ as *mut libc::c_void,
999 &mut len,
1000 std::ptr::null_mut(),
1001 0,
1002 ) == 0
1003 {
1004 return total_size;
1005 } else {
1006 return 16u64 << 30; // Fallback: 16GB default
1007 }
1008 }
1009 }
1010
1011 #[cfg(all(target_os = "linux", not(target_arch = "wasm32")))]
1012 {
1013 // Linux: use sysinfo() system call
1014 unsafe {
1015 let mut info: libc::sysinfo = std::mem::zeroed();
1016 if libc::sysinfo(&mut info) == 0 {
1017 let total = info.totalram as u64 * info.mem_unit as u64;
1018 return total;
1019 }
1020 }
1021 }
1022
1023 #[cfg(target_os = "windows")]
1024 {
1025 use std::mem;
1026 use winapi::um::sysinfoapi::{GlobalMemoryStatusEx, MEMORYSTATUSEX};
1027 unsafe {
1028 let mut mem_status: MEMORYSTATUSEX = mem::zeroed();
1029 mem_status.dwLength = mem::size_of::<MEMORYSTATUSEX>() as u32;
1030 if GlobalMemoryStatusEx(&mut mem_status) != 0 {
1031 return mem_status.ullTotalPhys;
1032 }
1033 }
1034 }
1035
1036 // Embedded platforms: conservative memory size estimates
1037 #[cfg(target_arch = "avr")]
1038 {
1039 return 2u64 << 10; // 2KB for AVR (like Arduino Uno with 2KB RAM)
1040 }
1041
1042 #[cfg(target_arch = "msp430")]
1043 {
1044 return 1u64 << 10; // 1KB for MSP430 (typical low-power MCU)
1045 }
1046
1047 #[cfg(target_arch = "riscv32")]
1048 {
1049 return 32u64 << 10; // 32KB for RISC-V MCUs (like ESP32-C3 type devices)
1050 }
1051
1052 #[cfg(target_arch = "riscv64")]
1053 {
1054 return 128u64 << 10; // 128KB for RISC-V 64-bit systems (like our QEMU example)
1055 }
1056
1057 #[cfg(target_arch = "xtensa")]
1058 {
1059 return 256u64 << 10; // 256KB for Xtensa (like ESP32 with up to 520KB)
1060 }
1061
1062 #[cfg(all(target_arch = "arm", target_os = "none"))]
1063 {
1064 return 16u64 << 10; // 16KB for ARM Cortex-M (conservative estimate, M0+ typically has this capacity)
1065 }
1066
1067 // Default for unknown platforms
1068 2u64 << 30
1069}
1070
1071// No_std versions of log functions
1072#[cfg(target_os = "none")]
1073fn smart_try_flush_log() {
1074 // No logging in no_std
1075}
1076
1077// ========== Runtime Allocator Information ==========
1078
1079#[cfg(not(target_os = "none"))]
1080static ALLOCATOR_INFO: Lazy<AllocatorInfo> = Lazy::new(|| {
1081 let system_info = collect_system_info();
1082 let allocator_id = RUNTIME_ALLOCATOR_ID.load(Ordering::Acquire);
1083
1084 // If not yet initialized, trigger allocator selection once
1085 let final_allocator_id = if allocator_id == 0 {
1086 RuntimeAllocator::get_allocator_id()
1087 } else {
1088 allocator_id
1089 };
1090
1091 let (_, mut reason) = get_allocator_selection_result(&system_info);
1092
1093 // Determine type based on actually selected allocator ID (may differ due to feature disable)
1094 let allocator_type = match final_allocator_id {
1095 5 => AllocatorType::MimallocSecure,
1096 2 => AllocatorType::Mimalloc,
1097 4 => AllocatorType::EmbeddedHeap,
1098 _ => AllocatorType::System,
1099 };
1100
1101 // Add "selected by runtime analysis" prefix to actual allocator info, extract hardware info part
1102 let hardware_info = if reason.contains('(') && reason.contains(')') {
1103 reason
1104 .split_once('(')
1105 .and_then(|(_prefix, suffix)| suffix.split_once(')').map(|(info, _)| info))
1106 .unwrap_or("")
1107 } else {
1108 ""
1109 };
1110
1111 reason = match final_allocator_id {
1112 5 => format!(
1113 "mimalloc-secure selected by runtime hardware analysis ({})",
1114 hardware_info
1115 ),
1116 2 => format!(
1117 "mimalloc selected by runtime hardware analysis ({})",
1118 hardware_info
1119 ),
1120 4 => {
1121 // For embedded allocator, preserve the original compile-time selection info
1122 reason
1123 },
1124 _ => {
1125 // For system allocator, preserve the original detailed reason as-is
1126 // (already includes correct "compile-time selected" or platform-specific info)
1127 reason
1128 },
1129 };
1130
1131 AllocatorInfo {
1132 allocator_type,
1133 reason,
1134 system_info,
1135 }
1136});
1137
1138// Simplified allocator info for no_std
1139#[cfg(target_os = "none")]
1140static mut EMBEDDED_ALLOCATOR_INFO: Option<AllocatorInfo> = None;
1141
1142// ========== Public API ==========
1143
1144/// Ensure allocator information is ready
1145/// Internal function, ensures ALLOCATOR_INFO has been computed
1146#[cfg(not(target_os = "none"))]
1147fn ensure_allocator_info_ready() {
1148 let _ = std::panic::catch_unwind(|| {
1149 Lazy::force(&ALLOCATOR_INFO);
1150 });
1151}
1152
1153#[cfg(target_os = "none")]
1154fn ensure_allocator_info_ready() {
1155 unsafe {
1156 if EMBEDDED_ALLOCATOR_INFO.is_none() {
1157 let system_info = collect_system_info();
1158 EMBEDDED_ALLOCATOR_INFO = Some(AllocatorInfo {
1159 allocator_type: AllocatorType::EmbeddedHeap,
1160 reason: "embedded-alloc selected for no_std environment",
1161 system_info,
1162 });
1163 }
1164 }
1165}
1166
1167/// Returns information about the automatically selected allocator
1168///
1169/// Provides allocator type, selection rationale, and system information.
1170/// First call triggers hardware detection; subsequent calls return cached results.
1171///
1172/// # Example
1173///
1174/// ```rust
1175/// use auto_allocator;
1176///
1177/// let info = auto_allocator::get_allocator_info();
1178/// println!("Using: {:?}", info.allocator_type);
1179/// println!("Reason: {}", info.reason);
1180/// ```
1181#[cfg(not(target_os = "none"))]
1182pub fn get_allocator_info() -> &'static AllocatorInfo {
1183 smart_try_flush_log();
1184 ensure_allocator_info_ready();
1185 &ALLOCATOR_INFO
1186}
1187
1188#[cfg(target_os = "none")]
1189pub fn get_allocator_info() -> &'static AllocatorInfo {
1190 ensure_allocator_info_ready();
1191 unsafe { EMBEDDED_ALLOCATOR_INFO.as_ref().unwrap() }
1192}
1193
1194/// Get current allocator type
1195///
1196/// Returns the currently used allocator type, this is a simplified version of [`get_allocator_info()`].
1197/// If you only need to know the allocator type without other information, using this function is more concise.
1198///
1199/// # Return Value
1200///
1201/// Returns [`AllocatorType`] enum value, possible values:
1202/// - [`AllocatorType::Mimalloc`] - Microsoft-developed high-performance allocator
1203/// - [`AllocatorType::EmbeddedHeap`] - Embedded systems specific allocator
1204/// - [`AllocatorType::System`] - System default allocator
1205///
1206/// # Example
1207///
1208/// ```rust
1209/// use auto_allocator;
1210///
1211/// let allocator_type = auto_allocator::get_allocator_type();
1212///
1213/// // Simple allocator type check
1214/// if allocator_type == auto_allocator::AllocatorType::Mimalloc {
1215/// println!("Using high-performance mimalloc allocator");
1216/// }
1217///
1218/// // Or use match statement
1219/// match allocator_type {
1220/// auto_allocator::AllocatorType::Mimalloc => {
1221/// println!("mimalloc - optimal performance");
1222/// }
1223/// auto_allocator::AllocatorType::System => {
1224/// println!("system - maximum compatibility");
1225/// }
1226/// _ => println!("other allocator"),
1227/// }
1228/// ```
1229///
1230/// # Performance Notes
1231///
1232/// This function is slightly faster than [`get_allocator_info()`] because it only returns type information.
1233pub fn get_allocator_type() -> AllocatorType {
1234 smart_try_flush_log();
1235 ensure_allocator_info_ready();
1236 get_allocator_info().allocator_type
1237}
1238
1239/// Get allocator selection result and reason (internal function)
1240#[cfg(not(target_os = "none"))]
1241fn get_allocator_selection_result(system_info: &SystemInfo) -> (AllocatorType, String) {
1242 let total_mem = format_memory_size(system_info.total_memory_bytes);
1243
1244 if system_info.is_wasm {
1245 (
1246 AllocatorType::System,
1247 format!("system allocator - WASM environment ({} total RAM)", total_mem),
1248 )
1249 } else if system_info.is_debug {
1250 (
1251 AllocatorType::System,
1252 format!(
1253 "system allocator - debug build ({} cores, {} total RAM)",
1254 system_info.cpu_cores, total_mem
1255 ),
1256 )
1257 } else if is_embedded_target() {
1258 (
1259 AllocatorType::EmbeddedHeap,
1260 format!("embedded-alloc allocator - embedded environment ({} total RAM)", total_mem),
1261 )
1262 } else if system_info.os_type == "android" {
1263 (
1264 AllocatorType::System,
1265 format!(
1266 "Android platform - Scudo allocator (security-first, use-after-free protection) ({} cores, {} total RAM)",
1267 system_info.cpu_cores, total_mem
1268 ),
1269 )
1270 } else if system_info.os_type == "ios" {
1271 (
1272 AllocatorType::System,
1273 format!(
1274 "iOS platform - libmalloc allocator (Apple-optimized, memory pressure handling) ({} cores, {} total RAM)",
1275 system_info.cpu_cores, total_mem
1276 ),
1277 )
1278 } else if system_info.os_type == "freebsd" || system_info.os_type == "netbsd" {
1279 (
1280 AllocatorType::System,
1281 format!(
1282 "BSD platform - native jemalloc (highly optimized, deep system integration) ({} cores, {} total RAM)",
1283 system_info.cpu_cores, total_mem
1284 ),
1285 )
1286 } else if system_info.os_type == "openbsd" {
1287 (
1288 AllocatorType::System,
1289 format!(
1290 "OpenBSD platform - security-hardened allocator (exploit mitigation, aggressive hardening) ({} cores, {} total RAM)",
1291 system_info.cpu_cores, total_mem
1292 ),
1293 )
1294 } else if system_info.os_type == "solaris" || system_info.os_type == "illumos" {
1295 (
1296 AllocatorType::System,
1297 format!(
1298 "Solaris platform - libumem allocator (NUMA-aware, enterprise-grade performance) ({} cores, {} total RAM)",
1299 system_info.cpu_cores, total_mem
1300 ),
1301 )
1302 } else if system_info.cpu_cores >= 2 {
1303 (
1304 AllocatorType::Mimalloc,
1305 format!(
1306 "mimalloc allocator - high-performance multi-threaded environment ({} cores, {} total RAM)",
1307 system_info.cpu_cores, total_mem
1308 ),
1309 )
1310 } else {
1311 (
1312 AllocatorType::System,
1313 format!(
1314 "system allocator - low-performance environment ({} cores, {} total RAM)",
1315 system_info.cpu_cores, total_mem
1316 ),
1317 )
1318 }
1319}
1320
1321/// Simplified allocator selection for no_std environments
1322#[cfg(target_os = "none")]
1323fn get_allocator_selection_result(_system_info: &SystemInfo) -> (AllocatorType, &'static str) {
1324 (AllocatorType::EmbeddedHeap, "embedded-alloc selected for no_std environment")
1325}
1326
1327/// Get recommended allocator for current runtime environment
1328///
1329/// Based on current system hardware and environment re-analysis, returns recommended allocator type and selection reason.
1330/// Unlike [`get_allocator_info()`], this function re-performs hardware detection and analysis every time.
1331///
1332/// # Return Value
1333///
1334/// Returns a tuple `(AllocatorType, String)`:
1335/// - First element: recommended allocator type
1336/// - Second element: recommendation reason, including hardware information
1337///
1338/// # Usage
1339///
1340/// This function is mainly used for:
1341/// - Performance analysis and optimization recommendations
1342/// - Verifying if current allocator selection is optimal
1343/// - Re-evaluation after runtime environment changes
1344///
1345/// # Examples
1346///
1347/// ```rust
1348/// use auto_allocator;
1349///
1350/// let (recommended_type, reason) = auto_allocator::get_recommended_allocator();
1351///
1352/// println!("Recommended allocator: {:?}", recommended_type);
1353/// println!("Recommendation reason: {}", reason);
1354///
1355/// // Compare with current allocator
1356/// let current_type = auto_allocator::get_allocator_type();
1357/// if current_type == recommended_type {
1358/// println!("Current allocator is already optimal");
1359/// } else {
1360/// println!("Suggest switching to: {:?}", recommended_type);
1361/// }
1362/// ```
1363///
1364/// # Performance Notes
1365///
1366/// This function re-performs system hardware detection, with slightly higher overhead than [`get_allocator_info()`].
1367#[cfg(not(target_os = "none"))]
1368pub fn get_recommended_allocator() -> (AllocatorType, String) {
1369 smart_try_flush_log();
1370 let system_info = collect_system_info();
1371 get_allocator_selection_result(&system_info)
1372}
1373
1374#[cfg(target_os = "none")]
1375pub fn get_recommended_allocator() -> (AllocatorType, &'static str) {
1376 let system_info = collect_system_info();
1377 get_allocator_selection_result(&system_info)
1378}
1379
1380/// Check if current allocator is optimal for current environment
1381///
1382/// Compares currently used allocator with hardware environment recommended allocator,
1383/// determining if the best allocator has already been selected.
1384/// Used for performance optimization checks and configuration validation.
1385///
1386/// # Return Value
1387///
1388/// Returns a tuple `(bool, Option<String>)`:
1389/// - `(true, None)` - Current allocator is already optimal
1390/// - `(false, Some(suggestion))` - Current allocator is not optimal, includes optimization suggestion
1391///
1392/// # Usage
1393///
1394/// - **Performance audit** - Check if application uses optimal allocator
1395/// - **Environment validation** - Confirm allocator configuration in deployment environment
1396/// - **Optimization suggestions** - Get specific allocator optimization recommendations
1397/// - **Monitoring integration** - Integrate into monitoring systems to check configuration drift
1398///
1399/// # Examples
1400///
1401/// ```rust
1402/// use auto_allocator;
1403///
1404/// let (is_optimal, suggestion) = auto_allocator::check_allocator_optimization();
1405///
1406/// if is_optimal {
1407/// println!("✅ Current allocator configuration is optimal");
1408/// } else if let Some(advice) = suggestion {
1409/// println!("⚠️ Allocator configuration can be optimized:");
1410/// println!(" {}", advice);
1411/// }
1412/// ```
1413///
1414/// # Practical Application Scenarios
1415///
1416/// ```rust
1417/// use auto_allocator;
1418///
1419/// // Check allocator configuration at application startup
1420/// fn check_performance_config() {
1421/// let (is_optimal, suggestion) = auto_allocator::check_allocator_optimization();
1422///
1423/// if !is_optimal {
1424/// eprintln!("Warning: {}", suggestion.unwrap_or_default());
1425/// eprintln!("Recommend compiling in Release mode for optimal performance");
1426/// }
1427/// }
1428///
1429/// // Validate configuration in CI/CD
1430/// fn test_allocator_optimization() {
1431/// let (is_optimal, _) = auto_allocator::check_allocator_optimization();
1432/// assert!(is_optimal, "Allocator configuration not optimized to best state");
1433/// }
1434/// ```
1435///
1436/// # Performance Notes
1437///
1438/// This function needs to re-detect hardware and compare allocators, with slightly higher overhead than simple information retrieval functions.
1439#[cfg(not(target_os = "none"))]
1440pub fn check_allocator_optimization() -> (bool, Option<String>) {
1441 smart_try_flush_log();
1442 let current = get_allocator_type();
1443 let (recommended, reason) = get_recommended_allocator();
1444
1445 if current == recommended {
1446 (true, None)
1447 } else {
1448 let suggestion = format!(
1449 "Current: {:?}, Recommended: {:?} ({})",
1450 current, recommended, reason
1451 );
1452 (false, Some(suggestion))
1453 }
1454}
1455
1456#[cfg(target_os = "none")]
1457pub fn check_allocator_optimization() -> (bool, Option<&'static str>) {
1458 // In no_std, always optimal (embedded-alloc)
1459 (true, None)
1460}
1461
1462// WASM environment initialization
1463#[cfg(target_arch = "wasm32")]
1464use wasm_bindgen::prelude::*;
1465
1466/// Automatically initializes allocator information when WASM module loads
1467///
1468/// This function is called automatically via `#[wasm_bindgen(start)]` - no manual invocation needed.
1469#[cfg(target_arch = "wasm32")]
1470#[wasm_bindgen(start)]
1471pub fn wasm_auto_init() {
1472 ensure_allocator_info_ready();
1473}
1474