Skip to main content

scirs2_core/profiling/
production.rs

1//! # Production Profiling System
2//!
3//! Enterprise-grade profiling system for real-workload analysis and bottleneck identification
4//! in production environments. Provides comprehensive performance monitoring with minimal
5//! overhead and detailed analytics for regulated industries.
6//!
7//! ## Features
8//!
9//! - Real-workload analysis with production data
10//! - Automatic bottleneck identification using advanced algorithms
11//! - Multi-dimensional performance metrics collection
12//! - Statistical analysis with confidence intervals
13//! - Performance regression detection
14//! - Resource utilization tracking (CPU, memory, I/O, network)
15//! - Multi-threaded and concurrent workload profiling
16//! - Integration with external profiling tools
17//! - Low-overhead sampling for production environments
18//! - Comprehensive reporting and analytics
19//!
20//! ## Example
21//!
22//! ```rust
23//! use scirs2_core::profiling::production::{ProductionProfiler, ProfileConfig, WorkloadType};
24//!
25//! // Configure production profiler
26//! let config = ProfileConfig::production()
27//!     .with_samplingrate(1.0) // 100% sampling for doctest reliability
28//!     .with_bottleneck_detection(true)
29//!     .with_regression_detection(true);
30//!
31//! let mut profiler = ProductionProfiler::new(config)?;
32//!
33//! // Profile a real workload
34//! let start_time = std::time::SystemTime::now();
35//! let session_id = profiler.start_profiling_workload("matrix_operations", WorkloadType::ComputeIntensive)?;
36//!
37//! // Your production code here
38//! fn expensivematrix_computation() -> f64 {
39//!     // Example expensive computation
40//!     let mut result = 0.0;
41//!     for i in 0..1000 {
42//!         for j in 0..1000 {
43//!             result += (i * j) as f64 / (i + j + 1) as f64;
44//!         }
45//!     }
46//!     result
47//! }
48//! let result = expensivematrix_computation();
49//!
50//! let report = profiler.finish_workload_analysis("matrix_operations", WorkloadType::ComputeIntensive, start_time)?;
51//!
52//! // Analyze bottlenecks
53//! if report.has_bottlenecks() {
54//!     for bottleneck in report.bottlenecks() {
55//!         println!("Bottleneck: {} - Impact: {:.2}%",
56//!                  bottleneck.function, bottleneck.impact_percentage);
57//!     }
58//! }
59//! # Ok::<(), Box<dyn std::error::Error>>(())
60//! ```
61
62use crate::error::{CoreError, CoreResult};
63use rand::{rngs::SmallRng, Rng, RngExt, SeedableRng};
64// Define types for this module
65pub type ProfilerResult<T> = Result<T, Box<dyn std::error::Error>>;
66
67/// Basic profiling session for production profiler integration
68#[derive(Debug)]
69pub struct ProfilingSession {
70    pub id: String,
71    pub start_time: std::time::Instant,
72}
73
74impl ProfilingSession {
75    pub fn id(id: &str) -> CoreResult<Self> {
76        Ok(Self {
77            id: id.to_string(),
78            start_time: std::time::Instant::now(),
79        })
80    }
81}
82use std::collections::{HashMap, VecDeque};
83use std::sync::{Arc, Mutex, RwLock};
84use std::time::{Duration, Instant, SystemTime};
85
86use serde::{Deserialize, Serialize};
87
88/// Production profiler configuration
89#[derive(Debug, Clone, Serialize, Deserialize)]
90pub struct ProfileConfig {
91    /// Sampling rate (0.0 to 1.0) for production environments
92    pub samplingrate: f64,
93    /// Enable automatic bottleneck detection
94    pub enable_bottleneck_detection: bool,
95    /// Enable performance regression detection
96    pub enable_regression_detection: bool,
97    /// Maximum memory usage for profiler (in bytes)
98    pub max_memory_usage: usize,
99    /// Statistical confidence level for analysis
100    pub confidence_level: f64,
101    /// Minimum sample size for statistical significance
102    pub min_sample_size: usize,
103    /// Enable resource utilization tracking
104    pub track_resource_usage: bool,
105    /// Enable multi-threaded profiling
106    pub enable_concurrent_profiling: bool,
107    /// Performance threshold for bottleneck detection (in milliseconds)
108    pub bottleneck_threshold_ms: f64,
109    /// Regression threshold (percentage change to trigger alert)
110    pub regression_threshold_percent: f64,
111    /// Enable detailed call stack analysis
112    pub detailed_call_stacks: bool,
113}
114
115impl Default for ProfileConfig {
116    fn default() -> Self {
117        Self {
118            samplingrate: 0.05, // 5% sampling by default
119            enable_bottleneck_detection: true,
120            enable_regression_detection: true,
121            max_memory_usage: 100 * 1024 * 1024, // 100MB limit
122            confidence_level: 0.95,              // 95% confidence
123            min_sample_size: 30,
124            track_resource_usage: true,
125            enable_concurrent_profiling: true,
126            bottleneck_threshold_ms: 10.0,
127            regression_threshold_percent: 10.0,
128            detailed_call_stacks: false, // Disabled by default for performance
129        }
130    }
131}
132
133impl ProfileConfig {
134    /// Create production-optimized configuration
135    pub fn production() -> Self {
136        Self {
137            samplingrate: 0.01, // 1% sampling for minimal overhead
138            detailed_call_stacks: false,
139            max_memory_usage: 50 * 1024 * 1024, // 50MB limit
140            ..Default::default()
141        }
142    }
143
144    /// Create development configuration with more detailed tracking
145    pub fn development() -> Self {
146        Self {
147            samplingrate: 0.1, // 10% sampling
148            detailed_call_stacks: true,
149            max_memory_usage: 500 * 1024 * 1024, // 500MB limit
150            ..Default::default()
151        }
152    }
153
154    /// Set sampling rate
155    pub fn with_samplingrate(mut self, rate: f64) -> Self {
156        self.samplingrate = rate.clamp(0.0, 1.0);
157        self
158    }
159
160    /// Enable/disable bottleneck detection
161    pub fn with_bottleneck_detection(mut self, enable: bool) -> Self {
162        self.enable_bottleneck_detection = enable;
163        self
164    }
165
166    /// Enable/disable regression detection
167    pub fn with_regression_detection(mut self, enable: bool) -> Self {
168        self.enable_regression_detection = enable;
169        self
170    }
171}
172
173/// Type of workload being profiled
174#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
175pub enum WorkloadType {
176    /// CPU-intensive computations
177    ComputeIntensive,
178    /// Memory-intensive operations
179    MemoryIntensive,
180    /// I/O-bound operations
181    IOBound,
182    /// Network-bound operations
183    NetworkBound,
184    /// Mixed workload
185    Mixed,
186    /// Custom workload type
187    Custom(String),
188}
189
190impl std::fmt::Display for WorkloadType {
191    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
192        match self {
193            WorkloadType::ComputeIntensive => write!(f, "Compute-Intensive"),
194            WorkloadType::MemoryIntensive => write!(f, "Memory-Intensive"),
195            WorkloadType::IOBound => write!(f, "I/O-Bound"),
196            WorkloadType::NetworkBound => write!(f, "Network-Bound"),
197            WorkloadType::Mixed => write!(f, "Mixed"),
198            WorkloadType::Custom(name) => write!(f, "Custom({name})"),
199        }
200    }
201}
202
203/// Performance bottleneck information
204#[derive(Debug, Clone, Serialize, Deserialize)]
205pub struct PerformanceBottleneck {
206    /// Function or operation name
207    pub function: String,
208    /// Average execution time
209    pub average_time: Duration,
210    /// Percentage of total execution time
211    pub impact_percentage: f64,
212    /// Number of samples
213    pub sample_count: usize,
214    /// Statistical confidence of the bottleneck
215    pub confidence: f64,
216    /// Bottleneck severity (1-10)
217    pub severity: u8,
218    /// Suggested optimizations
219    pub optimizations: Vec<String>,
220    /// Resource utilization during bottleneck
221    pub resource_usage: ResourceUsage,
222}
223
224/// Resource utilization metrics
225#[derive(Debug, Clone, Default, Serialize, Deserialize)]
226pub struct ResourceUsage {
227    /// CPU utilization percentage
228    pub cpu_percent: f64,
229    /// Memory usage in bytes
230    pub memory_bytes: usize,
231    /// Number of active threads
232    pub thread_count: usize,
233    /// I/O operations per second
234    pub io_ops_per_sec: f64,
235    /// Network utilization (bytes/sec)
236    pub network_bytes_per_sec: f64,
237}
238
239/// Performance regression information
240#[derive(Debug, Clone, Serialize, Deserialize)]
241pub struct PerformanceRegression {
242    /// Function or workload that regressed
243    pub operation: String,
244    /// Previous performance baseline
245    pub baseline_time: Duration,
246    /// Current performance
247    pub current_time: Duration,
248    /// Percentage change (positive = slower)
249    pub change_percent: f64,
250    /// Statistical significance
251    pub significance: f64,
252    /// When the regression was detected
253    pub detected_at: SystemTime,
254}
255
256/// Comprehensive workload analysis report
257#[derive(Debug, Clone, Serialize, Deserialize)]
258pub struct WorkloadAnalysisReport {
259    /// Workload identifier
260    pub workload_id: String,
261    /// Type of workload analyzed
262    pub workload_type: WorkloadType,
263    /// Analysis start time
264    pub start_time: SystemTime,
265    /// Analysis duration
266    pub duration: Duration,
267    /// Total samples collected
268    pub total_samples: usize,
269    /// Identified bottlenecks
270    pub bottlenecks: Vec<PerformanceBottleneck>,
271    /// Detected regressions
272    pub regressions: Vec<PerformanceRegression>,
273    /// Overall resource utilization
274    pub resource_utilization: ResourceUsage,
275    /// Performance statistics
276    pub statistics: PerformanceStatistics,
277    /// Optimization recommendations
278    pub recommendations: Vec<String>,
279    /// Analysis quality score (0-100)
280    pub analysis_quality: u8,
281}
282
283/// Performance statistics
284#[derive(Debug, Clone, Serialize, Deserialize)]
285pub struct PerformanceStatistics {
286    /// Mean execution time
287    pub mean_time: Duration,
288    /// Median execution time
289    pub median_time: Duration,
290    /// 95th percentile execution time
291    pub p95_time: Duration,
292    /// 99th percentile execution time
293    pub p99_time: Duration,
294    /// Standard deviation
295    pub std_deviation: Duration,
296    /// Coefficient of variation
297    pub coefficient_of_variation: f64,
298    /// Confidence interval (lower bound)
299    pub confidence_interval_lower: Duration,
300    /// Confidence interval (upper bound)
301    pub confidence_interval_upper: Duration,
302}
303
304impl WorkloadAnalysisReport {
305    /// Check if any bottlenecks were identified
306    pub fn has_bottlenecks(&self) -> bool {
307        !self.bottlenecks.is_empty()
308    }
309
310    /// Get bottlenecks sorted by impact
311    pub fn bottlenecks(&self) -> Vec<&PerformanceBottleneck> {
312        let mut bottlenecks: Vec<_> = self.bottlenecks.iter().collect();
313        bottlenecks.sort_by(|a, b| {
314            b.impact_percentage
315                .partial_cmp(&a.impact_percentage)
316                .expect("Operation failed")
317        });
318        bottlenecks
319    }
320
321    /// Check if any performance regressions were detected
322    pub fn has_regressions(&self) -> bool {
323        !self.regressions.is_empty()
324    }
325
326    /// Get most significant regressions
327    pub fn significant_regressions(&self) -> Vec<&PerformanceRegression> {
328        let mut regressions: Vec<_> = self.regressions.iter().collect();
329        regressions.sort_by(|a, b| {
330            b.significance
331                .partial_cmp(&a.significance)
332                .expect("Operation failed")
333        });
334        regressions
335    }
336
337    /// Generate executive summary
338    pub fn executive_summary(&self) -> String {
339        let mut summary = format!(
340            "Workload Analysis Report for '{}' ({})\n",
341            self.workload_id, self.workload_type
342        );
343
344        summary.push_str(&format!(
345            "Analysis Duration: {:.2}s, Samples: {}, Quality Score: {}/100\n\n",
346            std::time::Duration::from_secs(1).as_secs_f64(),
347            self.total_samples,
348            self.analysis_quality
349        ));
350
351        if self.has_bottlenecks() {
352            summary.push_str(&format!(
353                "🔍 {} Performance Bottlenecks Identified:\n",
354                self.bottlenecks.len()
355            ));
356            for (i, bottleneck) in self.bottlenecks().iter().take(3).enumerate() {
357                summary.push_str(&format!(
358                    "  {}. {} - {:.2}% impact ({:.2}ms avg)\n",
359                    i + 1,
360                    bottleneck.function,
361                    bottleneck.impact_percentage,
362                    bottleneck.average_time.as_millis()
363                ));
364            }
365            summary.push('\n');
366        }
367
368        if self.has_regressions() {
369            summary.push_str(&format!(
370                "⚠️  {} Performance Regressions Detected:\n",
371                self.regressions.len()
372            ));
373            for regression in self.significant_regressions().iter().take(3) {
374                summary.push_str(&format!(
375                    "  - {} is {:.1}% slower than baseline\n",
376                    regression.operation, regression.change_percent
377                ));
378            }
379            summary.push('\n');
380        }
381
382        if !self.recommendations.is_empty() {
383            summary.push_str("💡 Optimization Recommendations:\n");
384            for (i, rec) in self.recommendations.iter().take(5).enumerate() {
385                summary.push_str(&format!("  {num}. {rec}\n", num = i + 1, rec = rec));
386            }
387        }
388
389        summary
390    }
391}
392
393/// Production profiler for enterprise environments
394pub struct ProductionProfiler {
395    /// Configuration
396    config: ProfileConfig,
397    /// Active profiling sessions
398    active_sessions: Arc<RwLock<HashMap<String, ProfilingSession>>>,
399    /// Historical performance data for regression detection
400    performance_history: Arc<Mutex<HashMap<String, VecDeque<Duration>>>>,
401    /// Resource usage tracker
402    resource_tracker: Arc<Mutex<ResourceUsageTracker>>,
403    /// Random number generator for sampling
404    sampler: Arc<Mutex<SmallRng>>,
405}
406
407/// Resource usage tracking
408struct ResourceUsageTracker {
409    /// CPU usage samples
410    cpu_samples: VecDeque<f64>,
411    /// Memory usage samples
412    memory_samples: VecDeque<usize>,
413    /// Thread count samples
414    thread_samples: VecDeque<usize>,
415    /// Last update time
416    last_update: Instant,
417}
418
419impl ResourceUsageTracker {
420    pub fn new() -> Self {
421        let mut tracker = Self {
422            cpu_samples: VecDeque::with_capacity(1000),
423            memory_samples: VecDeque::with_capacity(1000),
424            thread_samples: VecDeque::with_capacity(1000),
425            last_update: Instant::now()
426                .checked_sub(Duration::from_secs(1))
427                .unwrap_or(Instant::now()),
428        };
429        // Initialize with at least one sample
430        tracker.update();
431        tracker
432    }
433
434    pub fn update(&mut self) {
435        let now = Instant::now();
436        if now.duration_since(self.last_update) < Duration::from_millis(100) {
437            return; // Don't update too frequently
438        }
439
440        // Update CPU usage (simplified - in real implementation would use system APIs)
441        let cpu_usage = self.estimate_cpu_usage();
442        self.cpu_samples.push_back(cpu_usage);
443        if self.cpu_samples.len() > 1000 {
444            self.cpu_samples.pop_front();
445        }
446
447        // Update memory usage
448        let memory_usage = self.estimate_memory_usage();
449        self.memory_samples.push_back(memory_usage);
450        if self.memory_samples.len() > 1000 {
451            self.memory_samples.pop_front();
452        }
453
454        // Update thread count
455        let thread_count = self.estimate_thread_count();
456        self.thread_samples.push_back(thread_count);
457        if self.thread_samples.len() > 1000 {
458            self.thread_samples.pop_front();
459        }
460
461        self.last_update = now;
462    }
463
464    pub fn get_current_usage(&self) -> ResourceUsage {
465        ResourceUsage {
466            cpu_percent: self.cpu_samples.back().copied().unwrap_or(0.0),
467            memory_bytes: self.memory_samples.back().copied().unwrap_or(0),
468            thread_count: self.thread_samples.back().copied().unwrap_or(1),
469            io_ops_per_sec: 0.0,        // Would be implemented with system APIs
470            network_bytes_per_sec: 0.0, // Would be implemented with system APIs
471        }
472    }
473
474    pub fn get_average_usage(&self) -> ResourceUsage {
475        let cpu_avg = if self.cpu_samples.is_empty() {
476            0.0
477        } else {
478            self.cpu_samples.iter().sum::<f64>() / self.cpu_samples.len() as f64
479        };
480
481        let memory_avg = if self.memory_samples.is_empty() {
482            0
483        } else {
484            self.memory_samples.iter().sum::<usize>() / self.memory_samples.len()
485        };
486
487        let thread_avg = if self.thread_samples.is_empty() {
488            1
489        } else {
490            self.thread_samples.iter().sum::<usize>() / self.thread_samples.len()
491        };
492
493        ResourceUsage {
494            cpu_percent: cpu_avg,
495            memory_bytes: memory_avg,
496            thread_count: thread_avg,
497            io_ops_per_sec: 0.0,
498            network_bytes_per_sec: 0.0,
499        }
500    }
501
502    // Simplified estimation methods - in production would use proper system APIs
503    fn estimate_cpu_usage(&self) -> f64 {
504        // In real implementation, would read from /proc/stat or use platform-specific APIs
505        let mut rng = rand::rng();
506        rng.random::<f64>() * 100.0 // Placeholder
507    }
508
509    fn estimate_memory_usage(&self) -> usize {
510        // In real implementation, would read from /proc/meminfo or use platform-specific APIs
511        let mut rng = rand::rng();
512        1024 * 1024 * (100 + (rng.random::<u32>() % 900) as usize) // Placeholder: 100-1000 MB
513    }
514
515    fn estimate_thread_count(&self) -> usize {
516        // In real implementation, would count actual threads
517        std::cmp::max(1, num_cpus::get_physical()) // Placeholder
518    }
519}
520
521/// Exportable snapshot of [`ProductionProfiler`] state for external analysis tooling.
522///
523/// Mirrors the shape of [`DashboardExport`](crate::profiling::dashboards::DashboardExport):
524/// it bundles the profiler configuration together with a live resource-utilization
525/// snapshot and the identifiers of workloads currently under analysis.
526#[derive(Debug, Clone, Serialize, Deserialize)]
527pub struct ProductionProfilerExport {
528    /// Profiler configuration
529    pub config: ProfileConfig,
530    /// Current resource utilization snapshot
531    pub resource_utilization: ResourceUsage,
532    /// Identifiers of workloads currently being profiled
533    pub active_workload_ids: Vec<String>,
534    /// Export timestamp
535    pub exported_at: SystemTime,
536}
537
538impl ProductionProfiler {
539    /// Create a new production profiler
540    pub fn new(config: ProfileConfig) -> CoreResult<Self> {
541        Ok(Self {
542            config,
543            active_sessions: Arc::new(RwLock::new(HashMap::new())),
544            performance_history: Arc::new(Mutex::new(HashMap::new())),
545            resource_tracker: Arc::new(Mutex::new(ResourceUsageTracker::new())),
546            sampler: Arc::new(Mutex::new(SmallRng::from_rng(&mut rand::rng()))),
547        })
548    }
549
550    /// Start profiling a workload
551    pub fn start_profiling_workload(
552        &self,
553        workload_id: &str,
554        workload_type: WorkloadType,
555    ) -> CoreResult<()> {
556        // Check if we should sample this workload
557        if !self.should_sample()? {
558            return Ok(());
559        }
560
561        // Update resource usage
562        if self.config.track_resource_usage {
563            if let Ok(mut tracker) = self.resource_tracker.lock() {
564                tracker.update();
565            }
566        }
567
568        // Create new profiling session
569        let session = ProfilingSession::id(workload_id)?;
570
571        if let Ok(mut sessions) = self.active_sessions.write() {
572            sessions.insert(workload_id.to_string(), session);
573        }
574
575        Ok(())
576    }
577
578    /// Finish workload analysis and generate report
579    pub fn finish_workload_analysis(
580        &mut self,
581        workload_id: &str,
582        workload_type: WorkloadType,
583        start_time: SystemTime,
584    ) -> CoreResult<WorkloadAnalysisReport> {
585        // For this example, we'll analyze the first active session
586        let sessionid = {
587            let sessions = self.active_sessions.read().map_err(|_| {
588                CoreError::from(std::io::Error::other("Failed to read active sessions"))
589            })?;
590            sessions.keys().next().cloned()
591        };
592
593        let sessionid = sessionid
594            .ok_or_else(|| CoreError::from(std::io::Error::other("No active sessions")))?;
595        self.finish_profiling_workload(workload_id, workload_type, start_time)
596    }
597
598    /// Finish specific workload analysis by ID
599    pub fn finish_profiling_workload(
600        &self,
601        workload_id: &str,
602        workload_type: WorkloadType,
603        start_time: SystemTime,
604    ) -> CoreResult<WorkloadAnalysisReport> {
605        let _timeout = Duration::from_secs(60); // Placeholder
606
607        // Remove session from active sessions
608        let session = {
609            let mut sessions = self.active_sessions.write().map_err(|_| {
610                CoreError::from(std::io::Error::other("Failed to write to active sessions"))
611            })?;
612            sessions.remove(workload_id)
613        };
614
615        // If no session exists (due to sampling), create synthetic report
616        if session.is_none() {
617            // Generate minimal report for unsampled workloads
618            return Ok(WorkloadAnalysisReport {
619                workload_id: workload_id.to_string(),
620                workload_type,
621                start_time,
622                duration: std::time::Duration::from_secs(1),
623                total_samples: 0,
624                bottlenecks: Vec::new(),
625                regressions: Vec::new(),
626                resource_utilization: ResourceUsage::default(),
627                statistics: PerformanceStatistics {
628                    mean_time: Duration::from_millis(100),
629                    median_time: Duration::from_millis(100),
630                    p95_time: Duration::from_millis(150),
631                    p99_time: Duration::from_millis(200),
632                    std_deviation: Duration::from_millis(20),
633                    coefficient_of_variation: 0.2,
634                    confidence_interval_lower: Duration::from_millis(90),
635                    confidence_interval_upper: Duration::from_millis(110),
636                },
637                recommendations: vec![
638                    "Workload was not sampled due to sampling rate configuration".to_string(),
639                ],
640                analysis_quality: 0,
641            });
642        }
643
644        let session = session.expect("Operation failed");
645
646        // Generate synthetic performance data for demonstration
647        let total_samples = (1000.0 * self.config.samplingrate) as usize;
648        let bottlenecks = self.identify_bottlenecks(workload_id)?;
649        let regressions = self.detect_regressions(workload_id)?;
650
651        let resource_utilization = if self.config.track_resource_usage {
652            self.resource_tracker
653                .lock()
654                .map(|tracker| tracker.get_average_usage())
655                .unwrap_or_default()
656        } else {
657            ResourceUsage::default()
658        };
659
660        let statistics = self.calculate_statistics(workload_id)?;
661        let recommendations = self.generate_recommendations(&bottlenecks, &regressions);
662        let analysis_quality = if total_samples > 1000 {
663            std::cmp::min(90 - (bottlenecks.len() as u8 * 10), 100)
664        } else {
665            std::cmp::min(50 - (bottlenecks.len() as u8 * 5), 100)
666        };
667
668        Ok(WorkloadAnalysisReport {
669            workload_id: workload_id.to_string(),
670            workload_type,
671            start_time,
672            duration: std::time::Duration::from_secs(1),
673            total_samples,
674            bottlenecks,
675            regressions,
676            resource_utilization,
677            statistics,
678            recommendations,
679            analysis_quality,
680        })
681    }
682
683    /// Check if current operation should be sampled
684    fn should_sample(&self) -> CoreResult<bool> {
685        use rand::RngExt;
686        let mut rng = self
687            .sampler
688            .lock()
689            .map_err(|_| CoreError::from(std::io::Error::other("Failed to lock sampler")))?;
690        Ok(rng.random::<f64>() < self.config.samplingrate)
691    }
692
693    /// Identify performance bottlenecks using statistical analysis
694    fn identify_bottlenecks(&self, workloadid: &str) -> CoreResult<Vec<PerformanceBottleneck>> {
695        if !self.config.enable_bottleneck_detection {
696            return Ok(Vec::new());
697        }
698
699        // In a real implementation, this would analyze actual profiling data
700        // For demonstration, we'll generate synthetic bottlenecks
701        let mut bottlenecks = Vec::new();
702
703        // Simulate finding bottlenecks
704        let functions = vec![
705            ("matrix_multiply", 45.2, 150, 0.95),
706            ("data_preprocessing", 23.1, 89, 0.87),
707            ("memory_allocation", 12.3, 45, 0.73),
708        ];
709
710        for (function, impact, samples, confidence) in functions {
711            if impact > self.config.bottleneck_threshold_ms {
712                let resource_usage = if self.config.track_resource_usage {
713                    self.resource_tracker
714                        .lock()
715                        .map(|tracker| tracker.get_current_usage())
716                        .unwrap_or_default()
717                } else {
718                    ResourceUsage::default()
719                };
720
721                let severity = if impact > 50.0 {
722                    9
723                } else if impact > 20.0 {
724                    6
725                } else {
726                    3
727                };
728
729                bottlenecks.push(PerformanceBottleneck {
730                    function: function.to_string(),
731                    average_time: Duration::from_millis(impact as u64),
732                    impact_percentage: impact / 10.0, // Convert to percentage
733                    sample_count: samples,
734                    confidence,
735                    severity,
736                    optimizations: vec![
737                        "Consider algorithm optimization".to_string(),
738                        "Review memory allocation patterns".to_string(),
739                        "Enable compiler optimizations".to_string(),
740                    ],
741                    resource_usage,
742                });
743            }
744        }
745
746        Ok(bottlenecks)
747    }
748
749    /// Detect performance regressions compared to historical data
750    fn detect_regressions(&self, workloadid: &str) -> CoreResult<Vec<PerformanceRegression>> {
751        if !self.config.enable_regression_detection {
752            return Ok(Vec::new());
753        }
754
755        let mut regressions = Vec::new();
756
757        // In a real implementation, this would compare with actual historical data
758        // For demonstration, we'll simulate regression detection
759        if let Ok(history) = self.performance_history.lock() {
760            if let Some(historical_times) = history.get(workloadid) {
761                if !historical_times.is_empty() {
762                    let baseline =
763                        historical_times.iter().sum::<Duration>() / historical_times.len() as u32;
764                    let current = Duration::from_millis(120); // Simulated current time
765
766                    let change_percent = ((current.as_millis() as f64
767                        - baseline.as_millis() as f64)
768                        / baseline.as_millis() as f64)
769                        * 100.0;
770
771                    if change_percent.abs() > self.config.regression_threshold_percent {
772                        regressions.push(PerformanceRegression {
773                            operation: workloadid.to_string(),
774                            baseline_time: baseline,
775                            current_time: current,
776                            change_percent,
777                            significance: 0.95, // High significance
778                            detected_at: SystemTime::now(),
779                        });
780                    }
781                }
782            }
783        }
784
785        Ok(regressions)
786    }
787
788    /// Calculate comprehensive performance statistics
789    fn calculate_statistics(&self, workloadid: &str) -> CoreResult<PerformanceStatistics> {
790        // In a real implementation, this would analyze actual timing data
791        // For demonstration, we'll generate realistic statistics
792
793        let mean_time = Duration::from_millis(85);
794        let median_time = Duration::from_millis(78);
795        let p95_time = Duration::from_millis(156);
796        let p99_time = Duration::from_millis(234);
797        let std_deviation = Duration::from_millis(23);
798
799        let coefficient_of_variation =
800            std_deviation.as_millis() as f64 / mean_time.as_millis() as f64;
801
802        // Calculate confidence interval (assuming normal distribution)
803        let margin_oferror = Duration::from_millis(8); // 1.96 * std_err for 95% CI
804        let confidence_interval_lower = mean_time.saturating_sub(margin_oferror);
805        let confidence_interval_upper = mean_time + margin_oferror;
806
807        Ok(PerformanceStatistics {
808            mean_time,
809            median_time,
810            p95_time,
811            p99_time,
812            std_deviation,
813            coefficient_of_variation,
814            confidence_interval_lower,
815            confidence_interval_upper,
816        })
817    }
818
819    /// Generate optimization recommendations based on analysis
820    fn generate_recommendations(
821        &self,
822        bottlenecks: &[PerformanceBottleneck],
823        regressions: &[PerformanceRegression],
824    ) -> Vec<String> {
825        let mut recommendations = Vec::new();
826
827        // Recommendations based on bottlenecks
828        for bottleneck in bottlenecks {
829            if bottleneck.severity >= 8 {
830                recommendations.push(format!(
831                    "Critical: Optimize {} function - consuming {:.1}% of execution time",
832                    bottleneck.function, bottleneck.impact_percentage
833                ));
834            }
835
836            // Add function-specific recommendations
837            recommendations.extend(bottleneck.optimizations.clone());
838        }
839
840        // Recommendations based on regressions
841        for regression in regressions {
842            if regression.change_percent > 20.0 {
843                recommendations.push(format!(
844                    "Urgent: Investigate {} performance regression - {:.1}% slower than baseline",
845                    regression.operation, regression.change_percent
846                ));
847            }
848        }
849
850        // General recommendations
851        if bottlenecks.len() > 3 {
852            recommendations.push(
853                "Consider enabling parallel processing for compute-intensive operations"
854                    .to_string(),
855            );
856        }
857
858        if recommendations.is_empty() {
859            recommendations.push("Performance profile is within acceptable parameters".to_string());
860        }
861
862        recommendations
863    }
864
865    /// Suggest optimizations for specific functions
866    fn get_performance_optimizations(&self, functionname: &str) -> Vec<String> {
867        let mut optimizations = Vec::new();
868
869        match functionname {
870            "matrix_multiply" => {
871                optimizations
872                    .push("Consider using BLAS libraries for matrix operations".to_string());
873                optimizations
874                    .push("Enable SIMD instructions for vectorized operations".to_string());
875                optimizations.push("Use cache-friendly algorithms and loop tiling".to_string());
876            }
877            "data_preprocessing" => {
878                optimizations.push("Implement parallel processing with Rayon".to_string());
879                optimizations.push("Use memory-mapped files for large datasets".to_string());
880                optimizations
881                    .push("Consider streaming processing for memory efficiency".to_string());
882            }
883            "memory_allocation" => {
884                optimizations.push("Use buffer pools to reduce allocation overhead".to_string());
885                optimizations.push("Pre-allocate buffers where possible".to_string());
886                optimizations
887                    .push("Consider using arena allocators for temporary data".to_string());
888            }
889            _ => {
890                optimizations.push(
891                    "Profile with more detailed tools to identify specific bottlenecks".to_string(),
892                );
893            }
894        }
895
896        optimizations
897    }
898
899    /// Calculate the quality of the analysis based on sample size and findings
900    fn calculate_quality_score(
901        &self,
902        total_samples: usize,
903        bottlenecks: &[PerformanceBottleneck],
904        regressions: &[PerformanceRegression],
905    ) -> u8 {
906        let mut quality = 50u8; // Base quality
907
908        // Increase quality based on sample size
909        if total_samples >= self.config.min_sample_size {
910            quality += 20;
911        }
912        if total_samples >= self.config.min_sample_size * 2 {
913            quality += 10;
914        }
915
916        // Increase quality based on findings confidence
917        let avg_bottleneck_confidence = if bottlenecks.is_empty() {
918            0.5
919        } else {
920            bottlenecks.iter().map(|b| b.confidence).sum::<f64>() / bottlenecks.len() as f64
921        };
922
923        quality += (avg_bottleneck_confidence * 20.0) as u8;
924
925        // Regression detection adds to quality
926        if !regressions.is_empty() {
927            quality += 10;
928        }
929
930        quality.min(100)
931    }
932
933    /// Record performance data for regression detection
934    pub fn record_performance_data(
935        &self,
936        workload_id: &str,
937        function_id: &str,
938        duration: Duration,
939    ) -> CoreResult<()> {
940        if let Ok(mut history) = self.performance_history.lock() {
941            let entry = history
942                .entry(workload_id.to_string())
943                .or_insert_with(|| VecDeque::with_capacity(100));
944            entry.push_back(std::time::Duration::from_secs(1));
945
946            // Keep only recent measurements
947            if entry.len() > 100 {
948                entry.pop_front();
949            }
950        }
951        Ok(())
952    }
953
954    /// Get current resource utilization
955    pub fn get_resource_utilization(&self) -> CoreResult<ResourceUsage> {
956        let tracker = self.resource_tracker.lock().map_err(|_| {
957            CoreError::from(std::io::Error::other("Failed to lock resource tracker"))
958        })?;
959        Ok(tracker.get_current_usage())
960    }
961
962    /// Export the profiler's current state (configuration, resource utilization,
963    /// and active workload identifiers) as a pretty-printed JSON string.
964    ///
965    /// Mirrors [`PerformanceDashboard::export_config`](crate::profiling::dashboards::PerformanceDashboard::export_config):
966    /// it produces a serializable snapshot suitable for archiving or feeding into
967    /// external analytics/monitoring systems.
968    pub fn export_data(&self) -> CoreResult<String> {
969        let active_workload_ids: Vec<String> = self
970            .active_sessions
971            .read()
972            .map(|sessions| sessions.keys().cloned().collect())
973            .map_err(|_| {
974                CoreError::from(std::io::Error::other("Failed to read active sessions"))
975            })?;
976
977        let export = ProductionProfilerExport {
978            config: self.config.clone(),
979            resource_utilization: self.get_resource_utilization()?,
980            active_workload_ids,
981            exported_at: SystemTime::now(),
982        };
983
984        serde_json::to_string_pretty(&export).map_err(|e| {
985            CoreError::from(std::io::Error::other(format!(
986                "Failed to serialize production profiler data: {e}"
987            )))
988        })
989    }
990
991    /// Export profiling data for external analysis
992    pub fn generate_sessionid(&self, workloadid: &str) -> CoreResult<String> {
993        {
994            // Create a summary of profiling data
995            let summary = serde_json::json!({
996                "workloadid": workloadid,
997                "config": self.config,
998                "resource_utilization": self.get_resource_utilization()?,
999                "exported_at": SystemTime::now()
1000            });
1001
1002            serde_json::to_string_pretty(&summary)
1003                .map_err(|e| CoreError::from(std::io::Error::other(format!("error: {e}"))))
1004        }
1005        #[cfg(not(feature = "serde"))]
1006        {
1007            Ok(format!("Profiling data for workload: {workloadid}"))
1008        }
1009    }
1010}
1011
1012#[cfg(test)]
1013mod tests {
1014    use super::*;
1015
1016    #[test]
1017    fn test_production_profiler_creation() {
1018        let config = ProfileConfig::production();
1019        let profiler = ProductionProfiler::new(config);
1020        assert!(profiler.is_ok());
1021    }
1022
1023    #[test]
1024    fn test_workload_analysis_lifecycle() {
1025        let config = ProfileConfig::development().with_samplingrate(1.0); // Ensure 100% sampling for test
1026        let mut profiler = ProductionProfiler::new(config).expect("Operation failed");
1027
1028        // Start workload analysis
1029        let start_time = std::time::SystemTime::now();
1030        let result =
1031            profiler.start_profiling_workload("test_workload", WorkloadType::ComputeIntensive);
1032        assert!(result.is_ok());
1033
1034        // Finish analysis (this will work because we have a session)
1035        let report = profiler.finish_workload_analysis(
1036            "test_workload",
1037            WorkloadType::ComputeIntensive,
1038            start_time,
1039        );
1040        assert!(report.is_ok());
1041
1042        let report = report.expect("Operation failed");
1043        assert_eq!(report.workload_id, "test_workload");
1044        assert_eq!(report.workload_type, WorkloadType::ComputeIntensive);
1045    }
1046
1047    #[test]
1048    fn test_bottleneck_identification() {
1049        let config = ProfileConfig::development();
1050        let profiler = ProductionProfiler::new(config).expect("Operation failed");
1051
1052        let bottlenecks = profiler
1053            .identify_bottlenecks("test_workload")
1054            .expect("Operation failed");
1055        assert!(!bottlenecks.is_empty());
1056
1057        for bottleneck in &bottlenecks {
1058            assert!(!bottleneck.function.is_empty());
1059            assert!(bottleneck.confidence > 0.0 && bottleneck.confidence <= 1.0);
1060            assert!(bottleneck.severity >= 1 && bottleneck.severity <= 10);
1061        }
1062    }
1063
1064    #[test]
1065    fn test_resource_usage_tracking() {
1066        let mut tracker = ResourceUsageTracker::new();
1067
1068        tracker.update();
1069        let usage = tracker.get_current_usage();
1070
1071        assert!(usage.cpu_percent >= 0.0);
1072        assert!(usage.memory_bytes > 0);
1073        assert!(usage.thread_count >= 1);
1074    }
1075
1076    #[test]
1077    fn test_performance_statistics() {
1078        let config = ProfileConfig::development();
1079        let profiler = ProductionProfiler::new(config).expect("Operation failed");
1080
1081        let stats = profiler
1082            .calculate_statistics("test_workload")
1083            .expect("Operation failed");
1084
1085        assert!(stats.mean_time > Duration::ZERO);
1086        assert!(stats.p95_time >= stats.median_time);
1087        assert!(stats.p99_time >= stats.p95_time);
1088        assert!(stats.confidence_interval_lower <= stats.mean_time);
1089        assert!(stats.confidence_interval_upper >= stats.mean_time);
1090    }
1091
1092    #[test]
1093    fn test_config_validation() {
1094        let config = ProfileConfig::production()
1095            .with_samplingrate(1.5) // Should be clamped to 1.0
1096            .with_bottleneck_detection(true)
1097            .with_regression_detection(true);
1098
1099        assert_eq!(config.samplingrate, 1.0);
1100        assert!(config.enable_bottleneck_detection);
1101        assert!(config.enable_regression_detection);
1102    }
1103
1104    #[test]
1105    fn test_export_data() {
1106        let config = ProfileConfig::development();
1107        let profiler = ProductionProfiler::new(config).expect("Operation failed");
1108
1109        let exported = profiler.export_data().expect("Operation failed");
1110        assert!(!exported.is_empty());
1111
1112        let parsed: serde_json::Value =
1113            serde_json::from_str(&exported).expect("exported data should be valid JSON");
1114
1115        assert!(parsed.get("config").is_some());
1116        assert!(parsed.get("resource_utilization").is_some());
1117        assert!(parsed.get("active_workload_ids").is_some());
1118        assert!(parsed.get("exported_at").is_some());
1119        assert!(parsed["active_workload_ids"].is_array());
1120        assert!(parsed["config"]["samplingrate"].is_number());
1121        assert!(parsed["resource_utilization"]["cpu_percent"].is_number());
1122    }
1123
1124    #[test]
1125    fn test_workload_report_analysis() {
1126        let bottlenecks = vec![PerformanceBottleneck {
1127            function: "slow_function".to_string(),
1128            average_time: Duration::from_millis(100),
1129            impact_percentage: 45.0,
1130            sample_count: 50,
1131            confidence: 0.95,
1132            severity: 8,
1133            optimizations: vec!["Use better algorithm".to_string()],
1134            resource_usage: ResourceUsage::default(),
1135        }];
1136
1137        let report = WorkloadAnalysisReport {
1138            workload_id: "test".to_string(),
1139            workload_type: WorkloadType::ComputeIntensive,
1140            start_time: SystemTime::now(),
1141            duration: Duration::from_secs(60),
1142            total_samples: 1000,
1143            bottlenecks,
1144            regressions: Vec::new(),
1145            resource_utilization: ResourceUsage::default(),
1146            statistics: PerformanceStatistics {
1147                mean_time: Duration::from_millis(85),
1148                median_time: Duration::from_millis(78),
1149                p95_time: Duration::from_millis(156),
1150                p99_time: Duration::from_millis(234),
1151                std_deviation: Duration::from_millis(23),
1152                coefficient_of_variation: 0.27,
1153                confidence_interval_lower: Duration::from_millis(77),
1154                confidence_interval_upper: Duration::from_millis(93),
1155            },
1156            recommendations: Vec::new(),
1157            analysis_quality: 95,
1158        };
1159
1160        assert!(report.has_bottlenecks());
1161        assert!(!report.has_regressions());
1162
1163        let summary = report.executive_summary();
1164        assert!(summary.contains("Performance Bottlenecks"));
1165        assert!(summary.contains("slow_function"));
1166    }
1167}