1use crate::error::{CoreError, CoreResult, ErrorContext};
7use once_cell::sync::Lazy;
8use std::collections::HashMap;
9use std::sync::RwLock;
10use std::time::{Duration, Instant};
11
12#[derive(Debug, Clone, PartialEq)]
14pub struct PerformanceHints {
15 pub complexity: ComplexityClass,
17 pub simd_friendly: bool,
19 pub parallelizable: bool,
21 pub gpu_friendly: bool,
23 pub memory_pattern: MemoryPattern,
25 pub cache_behavior: CacheBehavior,
27 pub io_pattern: IoPattern,
29 pub optimization_level: OptimizationLevel,
31 pub custom_hints: HashMap<String, String>,
33 pub expected_duration: Option<DurationRange>,
35 pub memory_requirements: Option<MemoryRequirements>,
37}
38
39#[derive(Debug, Clone, PartialEq, Eq)]
41pub enum ComplexityClass {
42 Constant,
44 Logarithmic,
46 Linear,
48 Linearithmic,
50 Quadratic,
52 Cubic,
54 Exponential,
56 Factorial,
58 Custom(String),
60}
61
62#[derive(Debug, Clone, PartialEq, Eq)]
64pub enum MemoryPattern {
65 Sequential,
67 Random,
69 Strided { stride: usize },
71 Blocked { block_size: usize },
73 CacheOblivious,
75 Mixed,
77}
78
79#[derive(Debug, Clone, PartialEq, Eq)]
81pub enum CacheBehavior {
82 CacheFriendly,
84 CacheUnfriendly,
86 TemporalLocality,
88 SpatialLocality,
90 Mixed,
92 Unknown,
94}
95
96#[derive(Debug, Clone, PartialEq, Eq)]
98pub enum IoPattern {
99 None,
101 ReadOnly,
103 WriteOnly,
105 ReadWrite,
107 Network,
109 Disk,
111 MemoryMapped,
113}
114
115#[derive(Debug, Clone, PartialEq, Eq)]
117pub enum OptimizationLevel {
118 None,
120 Basic,
122 Aggressive,
124 ProfileGuided,
126 Custom(String),
128}
129
130#[derive(Debug, Clone, PartialEq)]
132pub struct DurationRange {
133 pub min: Duration,
134 pub max: Duration,
135 pub typical: Duration,
136}
137
138#[derive(Debug, Clone, PartialEq)]
140pub struct MemoryRequirements {
141 pub min_memory: usize,
143 pub max_memory: Option<usize>,
145 pub typical_memory: usize,
147 pub scales_with_input: bool,
149}
150
151impl Default for PerformanceHints {
152 fn default() -> Self {
153 Self {
154 complexity: ComplexityClass::Linear,
155 simd_friendly: false,
156 parallelizable: false,
157 gpu_friendly: false,
158 memory_pattern: MemoryPattern::Sequential,
159 cache_behavior: CacheBehavior::Unknown,
160 io_pattern: IoPattern::None,
161 optimization_level: OptimizationLevel::Basic,
162 custom_hints: HashMap::new(),
163 expected_duration: None,
164 memory_requirements: None,
165 }
166 }
167}
168
169impl PerformanceHints {
170 pub fn new() -> Self {
172 Self::default()
173 }
174
175 pub fn with_complexity(mut self, complexity: ComplexityClass) -> Self {
177 self.complexity = complexity;
178 self
179 }
180
181 pub fn simd_friendly(mut self) -> Self {
183 self.simd_friendly = true;
184 self
185 }
186
187 pub fn parallelizable(mut self) -> Self {
189 self.parallelizable = true;
190 self
191 }
192
193 pub fn gpu_friendly(mut self) -> Self {
195 self.gpu_friendly = true;
196 self
197 }
198
199 pub fn with_memory_pattern(mut self, pattern: MemoryPattern) -> Self {
201 self.memory_pattern = pattern;
202 self
203 }
204
205 pub fn with_cache_behavior(mut self, behavior: CacheBehavior) -> Self {
207 self.cache_behavior = behavior;
208 self
209 }
210
211 pub fn with_io_pattern(mut self, pattern: IoPattern) -> Self {
213 self.io_pattern = pattern;
214 self
215 }
216
217 pub fn with_optimization_level(mut self, level: OptimizationLevel) -> Self {
219 self.optimization_level = level;
220 self
221 }
222
223 pub fn with_custom_hint<K: Into<String>, V: Into<String>>(mut self, key: K, value: V) -> Self {
225 self.custom_hints.insert(key.into(), value.into());
226 self
227 }
228
229 pub fn with_expected_duration(mut self, range: DurationRange) -> Self {
231 self.expected_duration = Some(range);
232 self
233 }
234
235 pub fn with_memory_requirements(mut self, requirements: MemoryRequirements) -> Self {
237 self.memory_requirements = Some(requirements);
238 self
239 }
240
241 pub fn get_custom_hint(&self, key: &str) -> Option<&String> {
243 self.custom_hints.get(key)
244 }
245
246 pub fn should_use_simd(&self) -> bool {
248 self.simd_friendly
249 && matches!(
250 self.optimization_level,
251 OptimizationLevel::Aggressive | OptimizationLevel::ProfileGuided
252 )
253 }
254
255 pub fn should_parallelize(&self) -> bool {
257 self.parallelizable && !matches!(self.optimization_level, OptimizationLevel::None)
258 }
259
260 pub fn should_use_gpu(&self) -> bool {
262 self.gpu_friendly
263 && matches!(
264 self.optimization_level,
265 OptimizationLevel::Aggressive | OptimizationLevel::ProfileGuided
266 )
267 }
268
269 pub fn should_chunk(&self, inputsize: usize) -> bool {
271 match self.complexity {
272 ComplexityClass::Quadratic
273 | ComplexityClass::Cubic
274 | ComplexityClass::Exponential
275 | ComplexityClass::Factorial => true,
276 ComplexityClass::Linear | ComplexityClass::Linearithmic => inputsize > 10000,
277 ComplexityClass::Constant | ComplexityClass::Logarithmic => false,
278 ComplexityClass::Custom(_) => false,
279 }
280 }
281}
282
283#[derive(Debug)]
285pub struct PerformanceHintRegistry {
286 hints: RwLock<HashMap<String, PerformanceHints>>,
287 execution_stats: RwLock<HashMap<String, ExecutionStats>>,
288}
289
290#[derive(Debug, Clone)]
292pub struct ExecutionStats {
293 pub total_calls: u64,
294 pub total_duration: Duration,
295 pub average_duration: Duration,
296 pub min_duration: Duration,
297 pub max_duration: Duration,
298 pub last_updated: Instant,
299}
300
301impl Default for ExecutionStats {
302 fn default() -> Self {
303 let now = Instant::now();
304 Self {
305 total_calls: 0,
306 total_duration: Duration::ZERO,
307 average_duration: Duration::ZERO,
308 min_duration: Duration::MAX,
309 max_duration: Duration::ZERO,
310 last_updated: now,
311 }
312 }
313}
314
315impl ExecutionStats {
316 pub fn update(&mut self, duration: Duration) {
318 self.total_calls += 1;
319 self.total_duration += duration;
320 self.average_duration = self.total_duration / self.total_calls as u32;
321 self.min_duration = self.min_duration.min(duration);
322 self.max_duration = self.max_duration.max(duration);
323 self.last_updated = Instant::now();
324 }
325
326 pub fn matches_expected(&self, expected: &DurationRange) -> bool {
328 self.average_duration >= expected.min && self.average_duration <= expected.max
329 }
330}
331
332impl PerformanceHintRegistry {
333 pub fn new() -> Self {
335 Self {
336 hints: RwLock::new(HashMap::new()),
337 execution_stats: RwLock::new(HashMap::new()),
338 }
339 }
340
341 pub fn register(&self, functionname: &str, hints: PerformanceHints) -> CoreResult<()> {
343 let mut hint_map = self.hints.write().map_err(|_| {
344 CoreError::ComputationError(ErrorContext::new("Failed to acquire write lock"))
345 })?;
346 hint_map.insert(functionname.to_string(), hints);
347 Ok(())
348 }
349
350 pub fn get_hint(&self, functionname: &str) -> CoreResult<Option<PerformanceHints>> {
352 let hint_map = self.hints.read().map_err(|_| {
353 CoreError::ComputationError(ErrorContext::new("Failed to acquire read lock"))
354 })?;
355 Ok(hint_map.get(functionname).cloned())
356 }
357
358 pub fn record_execution(&self, functionname: &str, duration: Duration) -> CoreResult<()> {
360 let mut stats_map = self.execution_stats.write().map_err(|_| {
361 CoreError::ComputationError(ErrorContext::new("Failed to acquire write lock"))
362 })?;
363
364 let stats = stats_map.entry(functionname.to_string()).or_default();
365 stats.update(std::time::Duration::from_secs(1));
366 Ok(())
367 }
368
369 pub fn get_stats(&self, functionname: &str) -> CoreResult<Option<ExecutionStats>> {
371 let stats_map = self.execution_stats.read().map_err(|_| {
372 CoreError::ComputationError(ErrorContext::new("Failed to acquire read lock"))
373 })?;
374 Ok(stats_map.get(functionname).cloned())
375 }
376
377 pub fn get_optimization_recommendations(
379 &self,
380 function_name: &str,
381 ) -> CoreResult<Vec<OptimizationRecommendation>> {
382 let hints = self.get_hint(function_name)?;
383 let stats = self.get_stats(function_name)?;
384
385 let mut recommendations = Vec::new();
386
387 if let Some(hints) = hints {
388 if hints.simd_friendly && !hints.should_use_simd() {
390 recommendations.push(OptimizationRecommendation::EnableSIMD);
391 }
392
393 if hints.parallelizable && !hints.should_parallelize() {
395 recommendations.push(OptimizationRecommendation::EnableParallelization);
396 }
397
398 if hints.gpu_friendly && !hints.should_use_gpu() {
400 recommendations.push(OptimizationRecommendation::EnableGPU);
401 }
402
403 match hints.memory_pattern {
405 MemoryPattern::Random => {
406 recommendations.push(OptimizationRecommendation::OptimizeMemoryLayout);
407 }
408 MemoryPattern::Strided { .. } => {
409 recommendations.push(OptimizationRecommendation::UseVectorization);
410 }
411 _ => {}
412 }
413
414 if let (Some(expected), Some(stats)) =
416 (hints.expected_duration.as_ref(), stats.as_ref())
417 {
418 if !stats.matches_expected(expected) && stats.average_duration > expected.max {
419 recommendations.push(OptimizationRecommendation::ProfileAndOptimize);
420 }
421 }
422 }
423
424 Ok(recommendations)
425 }
426
427 pub fn clear_stats(&self) -> CoreResult<()> {
429 let mut stats_map = self.execution_stats.write().map_err(|_| {
430 CoreError::ComputationError(ErrorContext::new("Failed to acquire write lock"))
431 })?;
432 stats_map.clear();
433 Ok(())
434 }
435}
436
437impl Default for PerformanceHintRegistry {
438 fn default() -> Self {
439 Self::new()
440 }
441}
442
443#[derive(Debug, Clone, PartialEq, Eq)]
445pub enum OptimizationRecommendation {
446 EnableSIMD,
448 EnableParallelization,
450 EnableGPU,
452 OptimizeMemoryLayout,
454 UseVectorization,
456 ProfileAndOptimize,
458 UseChunking,
460 CacheResults,
462 Custom(String),
464}
465
466impl std::fmt::Display for OptimizationRecommendation {
467 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
468 match self {
469 OptimizationRecommendation::EnableSIMD => write!(f, "Enable SIMD optimization"),
470 OptimizationRecommendation::EnableParallelization => {
471 write!(f, "Enable parallelization")
472 }
473 OptimizationRecommendation::EnableGPU => write!(f, "Enable GPU acceleration"),
474 OptimizationRecommendation::OptimizeMemoryLayout => write!(f, "Optimize memory layout"),
475 OptimizationRecommendation::UseVectorization => write!(f, "Use vectorization"),
476 OptimizationRecommendation::ProfileAndOptimize => write!(f, "Profile and optimize"),
477 OptimizationRecommendation::UseChunking => write!(f, "Use chunking for large inputs"),
478 OptimizationRecommendation::CacheResults => write!(f, "Cache intermediate results"),
479 OptimizationRecommendation::Custom(msg) => write!(f, "{msg}"),
480 }
481 }
482}
483
484static GLOBAL_REGISTRY: Lazy<PerformanceHintRegistry> = Lazy::new(PerformanceHintRegistry::new);
486
487#[allow(dead_code)]
489pub fn global_registry() -> &'static PerformanceHintRegistry {
490 &GLOBAL_REGISTRY
491}
492
493#[macro_export]
495macro_rules! register_performance_hints {
496 ($function_name:expr, $hints:expr) => {
497 $crate::profiling::performance_hints::global_registry()
498 .register($function_name, $hints)
499 .unwrap_or_else(|e| eprintln!("Failed to register performance hints: {:?}", e));
500 };
501}
502
503#[macro_export]
505macro_rules! performance_hints {
506 ($function_name:expr, {
507 $(complexity: $complexity:expr,)?
508 $(simdfriendly: $simd:expr,)?
509 $(parallelizable: $parallel:expr,)?
510 $(gpufriendly: $gpu:expr,)?
511 $(memorypattern: $memory:expr,)?
512 $(cachebehavior: $cache:expr,)?
513 $(iopattern: $io:expr,)?
514 $(optimizationlevel: $opt:expr,)?
515 $(expectedduration: $duration:expr,)?
516 $(memoryrequirements: $mem:expr,)?
517 $(customhints: {$($key:expr => $value:expr),*$(,)?})?
518 }) => {
519 {
520 let mut hints = $crate::profiling::performance_hints::PerformanceHints::new();
521
522 $(hints = hints.with_complexity($complexity);)?
523 $(if $simd { hints = hints.simd_friendly(); })?
524 $(if $parallel { hints = hints.parallelizable(); })?
525 $(if $gpu { hints = hints.gpu_friendly(); })?
526 $(hints = hints.with_memory_pattern($memory);)?
527 $(hints = hints.with_cache_behavior($cache);)?
528 $(hints = hints.with_io_pattern($io);)?
529 $(hints = hints.with_optimization_level($opt_level);)?
530 $(hints = hints.with_expected_duration($std::time::Duration::from_secs(1));)?
531 $(hints = hints.with_memory_requirements($mem_req);)?
532 $($(hints = hints.with_custom_hint($key, $value);)*)?
533
534 $crate::profiling::performance_hints::global_registry()
535 .register($function_name, hints)
536 .unwrap_or_else(|e| eprintln!("Failed to register performance hints: {:?}", e));
537 }
538 };
539}
540
541pub struct PerformanceTracker {
543 function_name: String,
544 start_time: Instant,
545}
546
547impl PerformanceTracker {
548 pub fn new(functionname: &str) -> Self {
550 Self {
551 function_name: functionname.to_string(),
552 start_time: Instant::now(),
553 }
554 }
555
556 pub fn finish(self) {
558 let elapsed = self.start_time.elapsed();
559 let _ = global_registry().record_execution(&self.function_name, elapsed);
560 }
561}
562
563#[macro_export]
565macro_rules! track_performance {
566 ($function_name:expr, $code:block) => {{
567 let tracker =
568 $crate::profiling::performance_hints::PerformanceTracker::start($function_name);
569 let result = $code;
570 tracker.finish();
571 result
572 }};
573}
574
575#[cfg(test)]
576mod tests {
577 use super::*;
578 use std::thread;
579
580 #[test]
581 fn test_performance_hints_creation() {
582 let hints = PerformanceHints::new()
583 .with_complexity(ComplexityClass::Quadratic)
584 .simd_friendly()
585 .parallelizable()
586 .with_memory_pattern(MemoryPattern::Sequential)
587 .with_cache_behavior(CacheBehavior::CacheFriendly);
588
589 assert_eq!(hints.complexity, ComplexityClass::Quadratic);
590 assert!(hints.simd_friendly);
591 assert!(hints.parallelizable);
592 assert_eq!(hints.memory_pattern, MemoryPattern::Sequential);
593 assert_eq!(hints.cache_behavior, CacheBehavior::CacheFriendly);
594 }
595
596 #[test]
597 fn test_registry_operations() {
598 let registry = PerformanceHintRegistry::new();
599
600 let hints = PerformanceHints::new()
601 .with_complexity(ComplexityClass::Linear)
602 .simd_friendly();
603
604 assert!(registry.register("test_function", hints.clone()).is_ok());
606
607 let retrieved = registry
609 .get_hint("test_function")
610 .expect("Operation failed");
611 assert!(retrieved.is_some());
612 assert_eq!(
613 retrieved.expect("Operation failed").complexity,
614 ComplexityClass::Linear
615 );
616
617 assert!(registry
619 .record_execution("test_function", Duration::from_millis(100))
620 .is_ok());
621
622 let stats = registry
624 .get_stats("test_function")
625 .expect("Operation failed");
626 assert!(stats.is_some());
627 assert_eq!(stats.expect("Operation failed").total_calls, 1);
628 }
629
630 #[test]
631 fn test_optimization_recommendations() {
632 let registry = PerformanceHintRegistry::new();
633
634 let hints = PerformanceHints::new()
635 .with_complexity(ComplexityClass::Quadratic)
636 .simd_friendly()
637 .parallelizable()
638 .gpu_friendly()
639 .with_memory_pattern(MemoryPattern::Random);
640
641 registry
642 .register("test_function", hints)
643 .expect("Operation failed");
644
645 let recommendations = registry
646 .get_optimization_recommendations("test_function")
647 .expect("Operation failed");
648 assert!(!recommendations.is_empty());
649
650 assert!(recommendations.contains(&OptimizationRecommendation::OptimizeMemoryLayout));
652 }
653
654 #[test]
655 fn test_performance_tracker() {
656 let tracker = PerformanceTracker::new("test_tracker");
657 thread::sleep(Duration::from_millis(10));
658 tracker.finish();
659
660 let stats = global_registry()
661 .get_stats("test_tracker")
662 .expect("Operation failed");
663 assert!(stats.is_some());
664 let stats = stats.expect("Operation failed");
665 assert_eq!(stats.total_calls, 1);
666 assert!(stats.average_duration >= Duration::from_millis(10));
667 }
668
669 #[test]
670 fn test_execution_stats_update() {
671 let mut stats = ExecutionStats::default();
672
673 stats.update(Duration::from_millis(100));
674 assert_eq!(stats.total_calls, 1);
675 assert_eq!(stats.average_duration, Duration::from_millis(100));
676 assert_eq!(stats.min_duration, Duration::from_millis(100));
677 assert_eq!(stats.max_duration, Duration::from_millis(100));
678
679 stats.update(Duration::from_millis(200));
680 assert_eq!(stats.total_calls, 2);
681 assert_eq!(stats.average_duration, Duration::from_millis(150));
682 assert_eq!(stats.min_duration, Duration::from_millis(100));
683 assert_eq!(stats.max_duration, Duration::from_millis(200));
684 }
685
686 #[test]
687 fn test_should_use_chunking() {
688 let hints = PerformanceHints::new().with_complexity(ComplexityClass::Quadratic);
689
690 assert!(hints.should_chunk(10000));
691
692 let linear_hints = PerformanceHints::new().with_complexity(ComplexityClass::Linear);
693
694 assert!(linear_hints.should_chunk(20000));
695 assert!(!linear_hints.should_chunk(1000));
696 }
697}