Skip to main content

tenflowers_core/ops/binary/
core.rs

1//! Core Binary Operations Infrastructure
2//!
3//! This module provides the fundamental traits, types, and registry for binary operations
4//! with advanced performance analytics and optimization tracking.
5
6use crate::{Result, TensorError};
7use scirs2_core::metrics::{Histogram, Timer};
8use std::sync::atomic::{AtomicU64, Ordering};
9use std::sync::{Arc, Mutex};
10
11/// Ultra-performance binary operation trait with vectorization support
12pub trait BinaryOp<T: Clone> {
13    fn apply(&self, a: T, b: T) -> T;
14    fn name(&self) -> &str;
15
16    /// Apply operation to entire slice with SIMD optimization
17    fn apply_slice(&self, a: &[T], b: &[T], output: &mut [T]) -> Result<()> {
18        // Default implementation - element-wise
19        if a.len() != b.len() || a.len() != output.len() {
20            return Err(TensorError::invalid_argument(
21                "Slice length mismatch for binary operation".to_string(),
22            ));
23        }
24        for i in 0..a.len() {
25            output[i] = self.apply(a[i].clone(), b[i].clone());
26        }
27        Ok(())
28    }
29
30    /// Check if operation supports SIMD acceleration
31    fn supports_simd(&self) -> bool {
32        false
33    }
34
35    /// Check if operation supports GPU acceleration
36    fn supports_gpu(&self) -> bool {
37        false
38    }
39
40    /// Get operation complexity for algorithm selection
41    fn complexity(&self) -> OpComplexity {
42        OpComplexity::Simple
43    }
44
45    /// Check if operation is associative (enables optimizations)
46    fn is_associative(&self) -> bool {
47        false
48    }
49
50    /// Check if operation is commutative (enables optimizations)
51    fn is_commutative(&self) -> bool {
52        false
53    }
54}
55
56/// Operation complexity levels for adaptive algorithm selection
57#[derive(Debug, Clone, Copy, PartialEq, Eq)]
58pub enum OpComplexity {
59    Simple,   // Basic arithmetic (+, -, *, /)
60    Moderate, // Comparisons, min/max
61    Complex,  // Transcendental functions
62    Advanced, // Custom complex operations
63}
64
65/// Ultra-performance binary operations registry and analytics
66pub struct BinaryOpRegistry {
67    /// Operation execution counters
68    op_counters: Arc<Mutex<std::collections::HashMap<String, AtomicU64>>>,
69    /// SIMD acceleration usage tracking
70    simd_usage: AtomicU64,
71    /// GPU acceleration usage tracking
72    gpu_usage: AtomicU64,
73    /// Parallel processing usage tracking
74    parallel_usage: AtomicU64,
75    /// Performance timer for operations
76    #[allow(dead_code)]
77    execution_timer: Timer,
78    /// Memory throughput tracking
79    memory_throughput: Histogram,
80}
81
82impl BinaryOpRegistry {
83    pub fn new() -> Self {
84        Self {
85            op_counters: Arc::new(Mutex::new(std::collections::HashMap::new())),
86            simd_usage: AtomicU64::new(0),
87            gpu_usage: AtomicU64::new(0),
88            parallel_usage: AtomicU64::new(0),
89            execution_timer: Timer::new("binary_ops.execution_time".to_string()),
90            memory_throughput: Histogram::new("binary_ops.memory_throughput".to_string()),
91        }
92    }
93
94    /// Record operation execution
95    pub fn record_operation(&self, op_name: &str, elements: usize, duration_ns: u64) {
96        // Increment operation counter
97        {
98            let mut counters = self
99                .op_counters
100                .lock()
101                .unwrap_or_else(|poisoned| poisoned.into_inner());
102            counters
103                .entry(op_name.to_string())
104                .or_insert_with(|| AtomicU64::new(0))
105                .fetch_add(1, Ordering::Relaxed);
106        }
107
108        // Calculate and record memory throughput (GB/s)
109        let bytes_processed = elements * std::mem::size_of::<f32>() * 2; // Input + output
110        let throughput_gbps = (bytes_processed as f64 * 1e9) / (duration_ns as f64 * 1e9);
111        self.memory_throughput.observe(throughput_gbps);
112    }
113
114    /// Record SIMD acceleration usage
115    pub fn record_simd_usage(&self) {
116        self.simd_usage.fetch_add(1, Ordering::Relaxed);
117    }
118
119    /// Record GPU acceleration usage
120    pub fn record_gpu_usage(&self) {
121        self.gpu_usage.fetch_add(1, Ordering::Relaxed);
122    }
123
124    /// Record parallel processing usage
125    pub fn record_parallel_usage(&self) {
126        self.parallel_usage.fetch_add(1, Ordering::Relaxed);
127    }
128
129    /// Get performance analytics
130    pub fn get_analytics(&self) -> BinaryOpAnalytics {
131        let counters = self
132            .op_counters
133            .lock()
134            .unwrap_or_else(|poisoned| poisoned.into_inner());
135        let op_counts: std::collections::HashMap<String, u64> = counters
136            .iter()
137            .map(|(k, v)| (k.clone(), v.load(Ordering::Relaxed)))
138            .collect();
139
140        BinaryOpAnalytics {
141            operation_counts: op_counts,
142            simd_accelerations: self.simd_usage.load(Ordering::Relaxed),
143            gpu_accelerations: self.gpu_usage.load(Ordering::Relaxed),
144            parallel_executions: self.parallel_usage.load(Ordering::Relaxed),
145            avg_memory_throughput: self.calculate_avg_throughput(),
146        }
147    }
148
149    fn calculate_avg_throughput(&self) -> f64 {
150        // Simplified calculation - in real implementation would use histogram stats
151        15.0 // GB/s average placeholder
152    }
153}
154
155impl Default for BinaryOpRegistry {
156    fn default() -> Self {
157        Self::new()
158    }
159}
160
161/// Performance analytics for binary operations
162#[derive(Debug, Clone)]
163pub struct BinaryOpAnalytics {
164    pub operation_counts: std::collections::HashMap<String, u64>,
165    pub simd_accelerations: u64,
166    pub gpu_accelerations: u64,
167    pub parallel_executions: u64,
168    pub avg_memory_throughput: f64,
169}
170
171/// Global binary operations registry
172static BINARY_OP_REGISTRY: std::sync::OnceLock<BinaryOpRegistry> = std::sync::OnceLock::new();
173
174/// Get global binary operations registry
175pub fn get_binary_op_registry() -> &'static BinaryOpRegistry {
176    BINARY_OP_REGISTRY.get_or_init(BinaryOpRegistry::new)
177}