moonpool_sim/runner/
report.rs

1//! Simulation metrics and reporting.
2//!
3//! This module provides types for collecting and reporting simulation results.
4
5use std::collections::HashMap;
6use std::fmt;
7use std::time::Duration;
8
9use crate::SimulationResult;
10use crate::chaos::AssertionStats;
11
12/// Core metrics collected during a simulation run.
13#[derive(Debug, Clone, PartialEq)]
14pub struct SimulationMetrics {
15    /// Wall-clock time taken for the simulation
16    pub wall_time: Duration,
17    /// Simulated logical time elapsed
18    pub simulated_time: Duration,
19    /// Number of events processed
20    pub events_processed: u64,
21}
22
23impl Default for SimulationMetrics {
24    fn default() -> Self {
25        Self {
26            wall_time: Duration::ZERO,
27            simulated_time: Duration::ZERO,
28            events_processed: 0,
29        }
30    }
31}
32
33/// Comprehensive report of a simulation run with statistical analysis.
34#[derive(Debug, Clone)]
35pub struct SimulationReport {
36    /// Number of iterations executed
37    pub iterations: usize,
38    /// Number of successful runs
39    pub successful_runs: usize,
40    /// Number of failed runs
41    pub failed_runs: usize,
42    /// Aggregated metrics across all runs
43    pub metrics: SimulationMetrics,
44    /// Individual metrics for each iteration
45    pub individual_metrics: Vec<SimulationResult<SimulationMetrics>>,
46    /// Seeds used for each iteration
47    pub seeds_used: Vec<u64>,
48    /// failed seeds
49    pub seeds_failing: Vec<u64>,
50    /// Aggregated assertion results across all iterations
51    pub assertion_results: HashMap<String, AssertionStats>,
52    /// Assertion validation violations (if any)
53    pub assertion_violations: Vec<String>,
54}
55
56impl SimulationReport {
57    /// Calculate the success rate as a percentage.
58    pub fn success_rate(&self) -> f64 {
59        if self.iterations == 0 {
60            0.0
61        } else {
62            (self.successful_runs as f64 / self.iterations as f64) * 100.0
63        }
64    }
65
66    /// Get the average wall time per iteration.
67    pub fn average_wall_time(&self) -> Duration {
68        if self.successful_runs == 0 {
69            Duration::ZERO
70        } else {
71            self.metrics.wall_time / self.successful_runs as u32
72        }
73    }
74
75    /// Get the average simulated time per iteration.
76    pub fn average_simulated_time(&self) -> Duration {
77        if self.successful_runs == 0 {
78            Duration::ZERO
79        } else {
80            self.metrics.simulated_time / self.successful_runs as u32
81        }
82    }
83
84    /// Get the average number of events processed per iteration.
85    pub fn average_events_processed(&self) -> f64 {
86        if self.successful_runs == 0 {
87            0.0
88        } else {
89            self.metrics.events_processed as f64 / self.successful_runs as f64
90        }
91    }
92}
93
94impl fmt::Display for SimulationReport {
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        writeln!(f, "=== Simulation Report ===")?;
97        writeln!(f, "Iterations: {}", self.iterations)?;
98        writeln!(f, "Successful: {}", self.successful_runs)?;
99        writeln!(f, "Failed: {}", self.failed_runs)?;
100        writeln!(f, "Success Rate: {:.2}%", self.success_rate())?;
101        writeln!(f)?;
102        writeln!(f, "Average Wall Time: {:?}", self.average_wall_time())?;
103        writeln!(
104            f,
105            "Average Simulated Time: {:?}",
106            self.average_simulated_time()
107        )?;
108        writeln!(
109            f,
110            "Average Events Processed: {:.1}",
111            self.average_events_processed()
112        )?;
113
114        if !self.seeds_failing.is_empty() {
115            writeln!(f)?;
116            writeln!(f, "Faulty seeds: {:?}", self.seeds_failing)?;
117        }
118
119        writeln!(f)?;
120
121        Ok(())
122    }
123}