1use std::{
2 collections::HashMap,
3 fs::File,
4 time::{Duration, Instant},
5};
6
7use stats::{mean, stddev};
8use tabled::{builder::Builder, Style};
9
10#[derive(Debug)]
11pub struct AggregatedStats {
13 _name: String,
14 party_names: Vec<String>,
15 timings: Vec<Vec<Timings>>,
16}
17
18pub struct TimingSummary {
20 timing_names: Vec<String>,
21 party_names: Vec<String>,
22 party_means: Vec<Vec<Option<f64>>>,
23 party_stdevs: Vec<Vec<Option<f64>>>,
24}
25
26impl TimingSummary {
27 pub fn print(&self) {
29 let mut builder = Builder::default();
30
31 builder.add_record(
33 ["Parties".to_string()]
34 .into_iter()
35 .chain(self.timing_names.iter().cloned()),
36 );
37
38 for ((means, stdevs), party_name) in self
40 .party_means
41 .iter()
42 .zip(&self.party_stdevs)
43 .zip(&self.party_names)
44 {
45 builder.add_record([party_name.clone()].into_iter().chain(
46 means.iter().zip(stdevs).map(|data| match data {
47 (&Some(mean), &Some(stdev)) => format!("{:.3} ± {:.3} s", mean, stdev),
48 _ => "".to_string(),
49 }),
50 ));
51 }
52
53 let table = builder.build().with(Style::modern());
54
55 println!("{}", table);
56 }
57}
58
59impl AggregatedStats {
60 pub fn new(name: String, party_names: Vec<String>) -> Self {
62 AggregatedStats {
63 _name: name,
64 party_names,
65 timings: vec![],
66 }
67 }
68
69 pub fn incorporate_party_stats(&mut self, party_stats: Vec<Timings>) {
71 self.timings.push(party_stats);
72 }
73
74 pub fn output_party_csv(&self, party_id: usize, csv_filename: &str) {
77 let writer = File::create(csv_filename).unwrap();
79 let mut csv_writer = csv::Writer::from_writer(writer);
80
81 let headers: Vec<String> = self.timings[0][party_id]
83 .measured_durations
84 .iter()
85 .map(|(name, _)| name.clone())
86 .collect();
87 csv_writer.write_record(&headers).unwrap();
88
89 for party_timings in &self.timings {
90 let durations: Vec<String> = party_timings[party_id]
91 .measured_durations
92 .iter()
93 .map(|(_, dur)| dur.as_micros().to_string())
94 .collect();
95 csv_writer.write_record(&durations).unwrap();
96 }
97
98 csv_writer.flush().unwrap();
99 }
100
101 pub fn summarize_timings(&self) -> TimingSummary {
103 let mut timing_names = vec![];
104 let mut party_timings_per_name: Vec<HashMap<String, Vec<f64>>> =
105 (0..self.party_names.len())
106 .map(|_| HashMap::new())
107 .collect();
108
109 for (party_timings, map) in self.timings.iter().zip(&mut party_timings_per_name) {
110 for timing in party_timings {
111 for (t, d) in &timing.measured_durations {
112 if !timing_names.contains(t) {
113 timing_names.push(t.clone());
114 }
115
116 map.entry(t.clone()).or_insert(vec![]).push(d.as_secs_f64());
117 }
118 }
119 }
120
121 println!("{:?}", party_timings_per_name);
122
123 let party_means = (0..self.party_names.len())
124 .map(|i| {
125 timing_names
126 .iter()
127 .map(|t| {
128 party_timings_per_name[i]
129 .get(t)
130 .map(|durations| mean(durations.iter().cloned()))
131 })
132 .collect::<Vec<_>>()
133 })
134 .collect();
135 let party_stdevs = (0..self.party_names.len())
136 .map(|i| {
137 timing_names
138 .iter()
139 .map(|t| {
140 party_timings_per_name[i]
141 .get(t)
142 .map(|durations| stddev(durations.iter().cloned()))
143 })
144 .collect::<Vec<_>>()
145 })
146 .collect();
147
148 TimingSummary {
149 timing_names,
150 party_names: self.party_names.clone(),
151 party_means,
152 party_stdevs,
153 }
154 }
155}
156
157#[derive(Debug)]
159pub struct Timings {
160 measured_durations: Vec<(String, Duration)>,
161}
162
163impl Timings {
164 pub(crate) fn new() -> Self {
165 Timings {
166 measured_durations: vec![],
167 }
168 }
169
170 pub(crate) fn write_duration(&mut self, name: String, duration: Duration) {
171 self.measured_durations.push((name, duration));
172 }
173}
174
175pub struct Timer {
177 name: String,
178 start_time: Instant,
179}
180
181impl Timer {
182 fn new(name: String) -> Self {
183 Timer {
184 name,
185 start_time: Instant::now(),
186 }
187 }
188
189 fn stop(&self) -> (String, Duration) {
190 (self.name.clone(), self.start_time.elapsed())
191 }
192}
193
194impl Timings {
195 pub fn create_timer(&self, name: &str) -> Timer {
197 Timer::new(String::from(name))
198 }
199
200 pub fn stop_timer(&mut self, timer: Timer) {
202 let (name, duration) = timer.stop();
203 self.write_duration(name, duration);
204 }
205}