Skip to main content

moirai_utils/
lib.rs

1//! Utility functions and data structures for Moirai concurrency library.
2//!
3//! This crate provides modular utility components organized by domain:
4//!
5//! - [`cache`] - Cache alignment utilities for performance optimization
6//! - [`atomic`] - Atomic operations and counters for lock-free programming
7//! - [`queue`] - Lock-free queues for high-performance data structures
8//! - [`memory`] - Memory utilities for cache prefetching
9
10#![cfg_attr(not(feature = "std"), no_std)]
11#![deny(missing_docs)]
12
13#[cfg(feature = "std")]
14extern crate std;
15
16#[cfg(not(feature = "std"))]
17extern crate alloc;
18
19// Modular organization following SOC and domain-oriented design
20pub mod atomic;
21pub mod cache;
22pub mod memory;
23pub mod queue;
24
25// SIMD optimizations for high-performance computing
26#[cfg(all(feature = "std", any(target_arch = "x86_64", target_arch = "aarch64")))]
27pub mod simd;
28
29// Re-export commonly used types for convenience
30pub use atomic::AtomicCounter;
31pub use cache::{align_to_cache_line, CacheAligned, CACHE_LINE_SIZE};
32pub use memory::{prefetch_read, prefetch_write};
33pub use queue::LockFreeQueue;
34
35// SIMD optimization counter and scalar contracts for performance tracking.
36#[cfg(all(feature = "std", any(target_arch = "x86_64", target_arch = "aarch64")))]
37pub use simd::{has_native_vector_path, SimdReal, SimdScalar};
38
39#[cfg(all(feature = "std", any(target_arch = "x86_64", target_arch = "aarch64")))]
40use std::sync::OnceLock;
41
42#[cfg(all(feature = "std", any(target_arch = "x86_64", target_arch = "aarch64")))]
43static GLOBAL_SIMD_COUNTER: OnceLock<SimdCounter> = OnceLock::new();
44
45/// Get the global SIMD performance counter instance.
46///
47/// This provides a singleton counter for tracking SIMD vs scalar operation usage
48/// across the entire application.
49#[cfg(all(feature = "std", any(target_arch = "x86_64", target_arch = "aarch64")))]
50pub fn global_simd_counter() -> &'static SimdCounter {
51    GLOBAL_SIMD_COUNTER.get_or_init(SimdCounter::new)
52}
53
54/// Performance counter for tracking SIMD optimization usage.
55///
56/// This counter tracks the ratio of vectorized vs scalar operations
57/// to help optimize performance-critical code paths.
58#[cfg(all(feature = "std", any(target_arch = "x86_64", target_arch = "aarch64")))]
59#[derive(Debug)]
60pub struct SimdCounter {
61    vectorized_ops: AtomicCounter,
62    scalar_ops: AtomicCounter,
63    vectorized_elements: AtomicCounter,
64    scalar_elements: AtomicCounter,
65}
66
67#[cfg(all(feature = "std", any(target_arch = "x86_64", target_arch = "aarch64")))]
68impl SimdCounter {
69    /// Create a new SIMD performance counter.
70    pub fn new() -> Self {
71        Self {
72            vectorized_ops: AtomicCounter::new(),
73            scalar_ops: AtomicCounter::new(),
74            vectorized_elements: AtomicCounter::new(),
75            scalar_elements: AtomicCounter::new(),
76        }
77    }
78
79    /// Record a vectorized operation with the number of elements processed.
80    pub fn record_vectorized_op(&self, elements: usize) {
81        self.vectorized_ops.increment();
82        self.vectorized_elements.add(elements);
83    }
84
85    /// Record a scalar operation with the number of elements processed.
86    pub fn record_scalar_op(&self, elements: usize) {
87        self.scalar_ops.increment();
88        self.scalar_elements.add(elements);
89    }
90
91    /// Get the total number of vectorized operations performed.
92    pub fn vectorized_ops(&self) -> usize {
93        self.vectorized_ops.get()
94    }
95
96    /// Get the total number of scalar operations performed.
97    pub fn scalar_ops(&self) -> usize {
98        self.scalar_ops.get()
99    }
100
101    /// Calculate the vectorization rate as a fraction of total operations.
102    pub fn vectorization_rate(&self) -> f64 {
103        let total = self.vectorized_ops() + self.scalar_ops();
104        if total == 0 {
105            0.0
106        } else {
107            self.vectorized_ops() as f64 / total as f64
108        }
109    }
110
111    /// Get basic statistics about SIMD usage.
112    pub fn get_stats(&self) -> (usize, usize, usize, usize) {
113        (
114            self.vectorized_ops(),
115            self.scalar_ops(),
116            self.vectorized_elements.get(),
117            self.scalar_elements.get(),
118        )
119    }
120
121    /// Reset all counters to zero.
122    pub fn reset(&self) {
123        self.vectorized_ops.reset();
124        self.scalar_ops.reset();
125        self.vectorized_elements.reset();
126        self.scalar_elements.reset();
127    }
128}
129
130#[cfg(all(feature = "std", any(target_arch = "x86_64", target_arch = "aarch64")))]
131impl Default for SimdCounter {
132    fn default() -> Self {
133        Self::new()
134    }
135}
136
137#[cfg(test)]
138mod integration_tests {
139    use super::*;
140
141    #[test]
142    fn test_modular_integration() {
143        // Test that all modules work together
144        let aligned_data = CacheAligned::new(42);
145        assert_eq!(*aligned_data, 42);
146
147        let counter = AtomicCounter::new();
148        counter.increment();
149        assert_eq!(counter.get(), 1);
150
151        let queue = LockFreeQueue::<i32>::with_capacity(4);
152        queue.enqueue(1);
153        assert_eq!(queue.try_dequeue(), Some(1));
154    }
155
156    #[test]
157    fn test_cache_line_alignment() {
158        assert_eq!(align_to_cache_line(1), CACHE_LINE_SIZE);
159        assert_eq!(align_to_cache_line(CACHE_LINE_SIZE), CACHE_LINE_SIZE);
160        assert_eq!(
161            align_to_cache_line(CACHE_LINE_SIZE + 1),
162            CACHE_LINE_SIZE * 2
163        );
164    }
165}