1use std::collections::HashMap;
30use std::sync::{Arc, Mutex, OnceLock};
31
32use crate::telemetry::LogLevel;
33
34static RUNTIME_CONFIG: OnceLock<Arc<Mutex<RuntimeConfigInternal>>> = OnceLock::new();
36
37#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
39pub enum DebugLevel {
40 None = 0,
42 Essential = 1,
44 Standard = 2,
46 Verbose = 3,
48 Paranoid = 4,
50}
51
52impl Default for DebugLevel {
53 fn default() -> Self {
54 #[cfg(debug_assertions)]
55 {
56 Self::Standard
57 }
58 #[cfg(not(debug_assertions))]
59 {
60 Self::Essential
61 }
62 }
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
67pub enum ValidationLevel {
68 Essential = 0,
70 Standard = 1,
72 Strict = 2,
74 Maximum = 3,
76}
77
78impl Default for ValidationLevel {
79 fn default() -> Self {
80 #[cfg(debug_assertions)]
81 {
82 Self::Strict
83 }
84 #[cfg(not(debug_assertions))]
85 {
86 Self::Standard
87 }
88 }
89}
90
91#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
93pub enum MonitoringScope {
94 None,
96 Minimal,
98 Standard,
100 Comprehensive,
102}
103
104impl Default for MonitoringScope {
105 fn default() -> Self {
106 Self::Standard
107 }
108}
109
110#[derive(Debug, Clone, Copy, PartialEq, Eq)]
112pub struct MemoryTrackingConfig {
113 pub track_allocations: bool,
115 pub track_deallocations: bool,
117 pub detect_leaks: bool,
119 pub analyze_patterns: bool,
121 pub max_tracked_allocations: usize,
123}
124
125impl Default for MemoryTrackingConfig {
126 fn default() -> Self {
127 Self {
128 track_allocations: cfg!(debug_assertions),
129 track_deallocations: cfg!(debug_assertions),
130 detect_leaks: cfg!(debug_assertions),
131 analyze_patterns: false, max_tracked_allocations: 10_000,
133 }
134 }
135}
136
137#[derive(Debug, Clone)]
139pub struct OperationConfig {
140 pub enable_metrics: bool,
142 pub enable_validation: bool,
144 pub timeout_ms: Option<u64>,
146 pub memory_limit_bytes: Option<usize>,
148}
149
150impl Default for OperationConfig {
151 fn default() -> Self {
152 Self {
153 enable_metrics: true,
154 enable_validation: true,
155 timeout_ms: None,
156 memory_limit_bytes: None,
157 }
158 }
159}
160
161#[derive(Debug, Clone)]
163struct RuntimeConfigInternal {
164 debug_level: DebugLevel,
166 validation_level: ValidationLevel,
168 monitoring_scope: MonitoringScope,
170 memory_tracking: MemoryTrackingConfig,
172 log_level: LogLevel,
174 operation_configs: HashMap<String, OperationConfig>,
176 is_testing: bool,
178 panic_on_warnings: bool,
180}
181
182impl Default for RuntimeConfigInternal {
183 fn default() -> Self {
184 Self {
185 debug_level: DebugLevel::default(),
186 validation_level: ValidationLevel::default(),
187 monitoring_scope: MonitoringScope::default(),
188 memory_tracking: MemoryTrackingConfig::default(),
189 log_level: LogLevel::Info,
190 operation_configs: HashMap::new(),
191 is_testing: std::env::var("RUST_TEST").is_ok(),
192 panic_on_warnings: false,
193 }
194 }
195}
196
197#[derive(Clone)]
202pub struct RuntimeConfig {
203 inner: Arc<Mutex<RuntimeConfigInternal>>,
204}
205
206impl RuntimeConfig {
207 pub fn global() -> Self {
218 let inner = RUNTIME_CONFIG
219 .get_or_init(|| Arc::new(Mutex::new(RuntimeConfigInternal::default())))
220 .clone();
221 Self { inner }
222 }
223
224 pub fn new() -> Self {
235 Self {
236 inner: Arc::new(Mutex::new(RuntimeConfigInternal::default())),
237 }
238 }
239
240 pub fn debug_level(&self) -> DebugLevel {
242 self.inner
243 .lock()
244 .expect("lock should not be poisoned")
245 .debug_level
246 }
247
248 pub fn set_debug_level(&self, level: DebugLevel) {
258 self.inner
259 .lock()
260 .expect("lock should not be poisoned")
261 .debug_level = level;
262 }
263
264 pub fn validation_level(&self) -> ValidationLevel {
266 self.inner
267 .lock()
268 .expect("lock should not be poisoned")
269 .validation_level
270 }
271
272 pub fn set_validation_level(&self, level: ValidationLevel) {
282 self.inner
283 .lock()
284 .expect("lock should not be poisoned")
285 .validation_level = level;
286 }
287
288 pub fn monitoring_scope(&self) -> MonitoringScope {
290 self.inner
291 .lock()
292 .expect("lock should not be poisoned")
293 .monitoring_scope
294 }
295
296 pub fn set_monitoring_scope(&self, scope: MonitoringScope) {
306 self.inner
307 .lock()
308 .expect("lock should not be poisoned")
309 .monitoring_scope = scope;
310 }
311
312 pub fn memory_tracking(&self) -> MemoryTrackingConfig {
314 self.inner
315 .lock()
316 .expect("lock should not be poisoned")
317 .memory_tracking
318 }
319
320 pub fn set_memory_tracking(&self, config: MemoryTrackingConfig) {
322 self.inner
323 .lock()
324 .expect("lock should not be poisoned")
325 .memory_tracking = config;
326 }
327
328 pub fn log_level(&self) -> LogLevel {
330 self.inner
331 .lock()
332 .expect("lock should not be poisoned")
333 .log_level
334 }
335
336 pub fn set_log_level(&self, level: LogLevel) {
347 self.inner
348 .lock()
349 .expect("lock should not be poisoned")
350 .log_level = level;
351 }
352
353 pub fn is_testing(&self) -> bool {
355 self.inner
356 .lock()
357 .expect("lock should not be poisoned")
358 .is_testing
359 }
360
361 pub fn set_testing(&self, testing: bool) {
363 self.inner
364 .lock()
365 .expect("lock should not be poisoned")
366 .is_testing = testing;
367 }
368
369 pub fn panic_on_warnings(&self) -> bool {
371 self.inner
372 .lock()
373 .expect("lock should not be poisoned")
374 .panic_on_warnings
375 }
376
377 pub fn set_panic_on_warnings(&self, panic: bool) {
379 self.inner
380 .lock()
381 .expect("lock should not be poisoned")
382 .panic_on_warnings = panic;
383 }
384
385 pub fn get_operation_config(&self, operation: &str) -> Option<OperationConfig> {
398 self.inner
399 .lock()
400 .expect("runtime config lock should not be poisoned")
401 .operation_configs
402 .get(operation)
403 .cloned()
404 }
405
406 pub fn set_operation_config(&self, operation: impl Into<String>, config: OperationConfig) {
419 self.inner
420 .lock()
421 .expect("runtime config lock should not be poisoned")
422 .operation_configs
423 .insert(operation.into(), config);
424 }
425
426 pub fn remove_operation_config(&self, operation: &str) -> Option<OperationConfig> {
428 self.inner
429 .lock()
430 .expect("runtime config lock should not be poisoned")
431 .operation_configs
432 .remove(operation)
433 }
434
435 pub fn clear_operation_configs(&self) {
437 self.inner
438 .lock()
439 .expect("lock should not be poisoned")
440 .operation_configs
441 .clear();
442 }
443
444 pub fn should_collect_metrics(&self, operation: &str) -> bool {
446 let guard = self.inner.lock().expect("lock should not be poisoned");
447
448 if let Some(op_config) = guard.operation_configs.get(operation) {
450 return op_config.enable_metrics;
451 }
452
453 match guard.monitoring_scope {
455 MonitoringScope::None => false,
456 MonitoringScope::Minimal => {
457 matches!(operation, "matmul" | "conv2d" | "backward")
459 }
460 MonitoringScope::Standard => {
461 !matches!(operation, "add" | "mul" | "sub" | "div")
463 }
464 MonitoringScope::Comprehensive => true,
465 }
466 }
467
468 pub fn should_validate(&self, operation: &str) -> bool {
470 let guard = self.inner.lock().expect("lock should not be poisoned");
471
472 if let Some(op_config) = guard.operation_configs.get(operation) {
474 return op_config.enable_validation;
475 }
476
477 guard.validation_level >= ValidationLevel::Standard
479 }
480
481 pub fn should_validate_essential(&self) -> bool {
483 let guard = self.inner.lock().expect("lock should not be poisoned");
484 guard.validation_level >= ValidationLevel::Essential
485 }
486
487 pub fn should_validate_standard(&self) -> bool {
489 let guard = self.inner.lock().expect("lock should not be poisoned");
490 guard.validation_level >= ValidationLevel::Standard
491 }
492
493 pub fn should_validate_strict(&self) -> bool {
495 let guard = self.inner.lock().expect("lock should not be poisoned");
496 guard.validation_level >= ValidationLevel::Strict
497 }
498
499 pub fn should_validate_maximum(&self) -> bool {
501 let guard = self.inner.lock().expect("lock should not be poisoned");
502 guard.validation_level >= ValidationLevel::Maximum
503 }
504
505 pub fn apply_preset(&self, preset: ConfigPreset) {
519 let mut guard = self.inner.lock().expect("lock should not be poisoned");
520 match preset {
521 ConfigPreset::Development => {
522 guard.debug_level = DebugLevel::Verbose;
523 guard.validation_level = ValidationLevel::Maximum;
524 guard.monitoring_scope = MonitoringScope::Comprehensive;
525 guard.memory_tracking = MemoryTrackingConfig {
526 track_allocations: true,
527 track_deallocations: true,
528 detect_leaks: true,
529 analyze_patterns: true,
530 max_tracked_allocations: 50_000,
531 };
532 guard.log_level = LogLevel::Debug;
533 guard.panic_on_warnings = false;
534 }
535 ConfigPreset::Testing => {
536 guard.debug_level = DebugLevel::Standard;
537 guard.validation_level = ValidationLevel::Strict;
538 guard.monitoring_scope = MonitoringScope::Standard;
539 guard.memory_tracking = MemoryTrackingConfig {
540 track_allocations: true,
541 track_deallocations: true,
542 detect_leaks: true,
543 analyze_patterns: false,
544 max_tracked_allocations: 10_000,
545 };
546 guard.log_level = LogLevel::Info;
547 guard.panic_on_warnings = true;
548 guard.is_testing = true;
549 }
550 ConfigPreset::Production => {
551 guard.debug_level = DebugLevel::None;
552 guard.validation_level = ValidationLevel::Essential;
553 guard.monitoring_scope = MonitoringScope::Minimal;
554 guard.memory_tracking = MemoryTrackingConfig {
555 track_allocations: false,
556 track_deallocations: false,
557 detect_leaks: false,
558 analyze_patterns: false,
559 max_tracked_allocations: 0,
560 };
561 guard.log_level = LogLevel::Warn;
562 guard.panic_on_warnings = false;
563 }
564 ConfigPreset::Profiling => {
565 guard.debug_level = DebugLevel::Essential;
566 guard.validation_level = ValidationLevel::Standard;
567 guard.monitoring_scope = MonitoringScope::Comprehensive;
568 guard.memory_tracking = MemoryTrackingConfig {
569 track_allocations: true,
570 track_deallocations: true,
571 detect_leaks: false,
572 analyze_patterns: true,
573 max_tracked_allocations: 100_000,
574 };
575 guard.log_level = LogLevel::Info;
576 guard.panic_on_warnings = false;
577 }
578 }
579 }
580
581 pub fn reset(&self) {
583 *self.inner.lock().expect("lock should not be poisoned") = RuntimeConfigInternal::default();
584 }
585
586 pub fn snapshot(&self) -> RuntimeConfigSnapshot {
588 let guard = self.inner.lock().expect("lock should not be poisoned");
589 RuntimeConfigSnapshot {
590 debug_level: guard.debug_level,
591 validation_level: guard.validation_level,
592 monitoring_scope: guard.monitoring_scope,
593 memory_tracking: guard.memory_tracking,
594 log_level: guard.log_level,
595 is_testing: guard.is_testing,
596 panic_on_warnings: guard.panic_on_warnings,
597 operation_count: guard.operation_configs.len(),
598 }
599 }
600}
601
602impl Default for RuntimeConfig {
603 fn default() -> Self {
604 Self::global()
605 }
606}
607
608#[derive(Debug, Clone, Copy, PartialEq, Eq)]
610pub enum ConfigPreset {
611 Development,
613 Testing,
615 Production,
617 Profiling,
619}
620
621#[derive(Debug, Clone)]
623pub struct RuntimeConfigSnapshot {
624 pub debug_level: DebugLevel,
625 pub validation_level: ValidationLevel,
626 pub monitoring_scope: MonitoringScope,
627 pub memory_tracking: MemoryTrackingConfig,
628 pub log_level: LogLevel,
629 pub is_testing: bool,
630 pub panic_on_warnings: bool,
631 pub operation_count: usize,
632}
633
634#[macro_export]
636macro_rules! torsh_debug_assert {
637 ($cond:expr) => {
638 if $crate::runtime_config::RuntimeConfig::global().debug_level() >= $crate::runtime_config::DebugLevel::Standard {
639 assert!($cond);
640 }
641 };
642 ($cond:expr, $($arg:tt)+) => {
643 if $crate::runtime_config::RuntimeConfig::global().debug_level() >= $crate::runtime_config::DebugLevel::Standard {
644 assert!($cond, $($arg)+);
645 }
646 };
647}
648
649#[macro_export]
651macro_rules! torsh_debug_assert_verbose {
652 ($cond:expr) => {
653 if $crate::runtime_config::RuntimeConfig::global().debug_level() >= $crate::runtime_config::DebugLevel::Verbose {
654 assert!($cond);
655 }
656 };
657 ($cond:expr, $($arg:tt)+) => {
658 if $crate::runtime_config::RuntimeConfig::global().debug_level() >= $crate::runtime_config::DebugLevel::Verbose {
659 assert!($cond, $($arg)+);
660 }
661 };
662}
663
664#[macro_export]
666macro_rules! torsh_assert_essential {
667 ($cond:expr) => {
668 if $crate::runtime_config::RuntimeConfig::global().debug_level() >= $crate::runtime_config::DebugLevel::Essential {
669 assert!($cond);
670 }
671 };
672 ($cond:expr, $($arg:tt)+) => {
673 if $crate::runtime_config::RuntimeConfig::global().debug_level() >= $crate::runtime_config::DebugLevel::Essential {
674 assert!($cond, $($arg)+);
675 }
676 };
677}
678
679#[cfg(test)]
680mod tests {
681 use super::*;
682
683 #[test]
684 fn test_runtime_config_creation() {
685 let config = RuntimeConfig::new();
686 assert_eq!(config.debug_level(), DebugLevel::default());
687 assert_eq!(config.validation_level(), ValidationLevel::default());
688 }
689
690 #[test]
691 fn test_debug_level_setting() {
692 let config = RuntimeConfig::new();
693 config.set_debug_level(DebugLevel::Paranoid);
694 assert_eq!(config.debug_level(), DebugLevel::Paranoid);
695 }
696
697 #[test]
698 fn test_validation_level_setting() {
699 let config = RuntimeConfig::new();
700 config.set_validation_level(ValidationLevel::Maximum);
701 assert_eq!(config.validation_level(), ValidationLevel::Maximum);
702 }
703
704 #[test]
705 fn test_monitoring_scope_setting() {
706 let config = RuntimeConfig::new();
707 config.set_monitoring_scope(MonitoringScope::Comprehensive);
708 assert_eq!(config.monitoring_scope(), MonitoringScope::Comprehensive);
709 }
710
711 #[test]
712 fn test_operation_config() {
713 let config = RuntimeConfig::new();
714
715 let op_config = OperationConfig {
716 enable_metrics: false,
717 enable_validation: true,
718 timeout_ms: Some(5000),
719 memory_limit_bytes: Some(1024 * 1024), };
721
722 config.set_operation_config("test_op", op_config.clone());
723
724 let retrieved = config
725 .get_operation_config("test_op")
726 .expect("get_operation_config should succeed");
727 assert!(!retrieved.enable_metrics);
728 assert!(retrieved.enable_validation);
729 assert_eq!(retrieved.timeout_ms, Some(5000));
730 assert_eq!(retrieved.memory_limit_bytes, Some(1024 * 1024));
731 }
732
733 #[test]
734 fn test_should_collect_metrics() {
735 let config = RuntimeConfig::new();
736
737 config.set_monitoring_scope(MonitoringScope::None);
739 assert!(!config.should_collect_metrics("matmul"));
740
741 config.set_monitoring_scope(MonitoringScope::Minimal);
742 assert!(config.should_collect_metrics("matmul"));
743 assert!(!config.should_collect_metrics("add"));
744
745 config.set_monitoring_scope(MonitoringScope::Comprehensive);
746 assert!(config.should_collect_metrics("add"));
747 }
748
749 #[test]
750 fn test_should_validate() {
751 let config = RuntimeConfig::new();
752
753 config.set_validation_level(ValidationLevel::Essential);
754 assert!(!config.should_validate("any_operation"));
755
756 config.set_validation_level(ValidationLevel::Standard);
757 assert!(config.should_validate("any_operation"));
758 }
759
760 #[test]
761 fn test_development_preset() {
762 let config = RuntimeConfig::new();
763 config.apply_preset(ConfigPreset::Development);
764
765 assert_eq!(config.debug_level(), DebugLevel::Verbose);
766 assert_eq!(config.validation_level(), ValidationLevel::Maximum);
767 assert_eq!(config.monitoring_scope(), MonitoringScope::Comprehensive);
768 assert!(config.memory_tracking().track_allocations);
769 }
770
771 #[test]
772 fn test_production_preset() {
773 let config = RuntimeConfig::new();
774 config.apply_preset(ConfigPreset::Production);
775
776 assert_eq!(config.debug_level(), DebugLevel::None);
777 assert_eq!(config.validation_level(), ValidationLevel::Essential);
778 assert_eq!(config.monitoring_scope(), MonitoringScope::Minimal);
779 assert!(!config.memory_tracking().track_allocations);
780 }
781
782 #[test]
783 fn test_testing_preset() {
784 let config = RuntimeConfig::new();
785 config.apply_preset(ConfigPreset::Testing);
786
787 assert_eq!(config.debug_level(), DebugLevel::Standard);
788 assert_eq!(config.validation_level(), ValidationLevel::Strict);
789 assert!(config.panic_on_warnings());
790 assert!(config.is_testing());
791 }
792
793 #[test]
794 fn test_snapshot() {
795 let config = RuntimeConfig::new();
796 config.set_debug_level(DebugLevel::Verbose);
797
798 let snapshot = config.snapshot();
799 assert_eq!(snapshot.debug_level, DebugLevel::Verbose);
800 }
801
802 #[test]
803 fn test_reset() {
804 let config = RuntimeConfig::new();
805 config.set_debug_level(DebugLevel::Paranoid);
806 config.reset();
807 assert_eq!(config.debug_level(), DebugLevel::default());
808 }
809
810 #[test]
811 fn test_clear_operation_configs() {
812 let config = RuntimeConfig::new();
813 config.set_operation_config("op1", OperationConfig::default());
814 config.set_operation_config("op2", OperationConfig::default());
815
816 config.clear_operation_configs();
817 assert!(config.get_operation_config("op1").is_none());
818 assert!(config.get_operation_config("op2").is_none());
819 }
820}