1use std::{
2 time::Duration,
3 collections::BTreeMap,
4};
5
6pub struct BlockStatReport {
7 name: String,
8 avg_time: Duration,
9 global_percents: f32,
10 relative_parent_percents: f32,
11 children: Vec<BlockStatReport>,
12}
13
14impl BlockStatReport {
15 pub fn build_string(&mut self, report: &mut String) {
16 self.build_string_recurse(report, 0, 0)
17 }
18
19 fn build_string_recurse(&mut self, report: &mut String, depth: usize, max_name_len: usize) {
20 let name = self.name.replace("<", "<").replace(">", ">");
21
22 *report += &format!(
23 concat!(
24 "<tr>",
25 "<td style=\"padding-left: {}\">{}</td>",
26 "<td>{:6.2} %</td>",
27 "<td>{:6.2} %</td>",
28 "<td>{:9.4} ms</td>",
29 "</tr>\n"
30 ),
31 depth*25, name, self.global_percents, self.relative_parent_percents, self.avg_time.as_secs_f32()*1000.0
32 );
33
34 self.children.sort_by(|a, b| b.relative_parent_percents.partial_cmp(&a.relative_parent_percents).unwrap());
35
36 for child in self.children.iter_mut() {
37 child.build_string_recurse(report, depth + 1, max_name_len);
38 }
39 }
40}
41
42
43pub struct BlockStat {
44 pub(crate) name: &'static str,
45 pub(crate) total_time: Duration,
46 pub(crate) measure_count: u32,
47 pub(crate) children: BTreeMap<usize, Box<BlockStat>>,
48}
49
50impl BlockStat {
51 pub fn new(name: &'static str) -> BlockStat {
52 BlockStat {
53 name,
54 total_time: Duration::from_millis(0),
55 measure_count: 0,
56 children: BTreeMap::new(),
57 }
58 }
59
60 pub fn build_report(&self) -> BlockStatReport {
61 self.build_report_recurse(self.total_time, self.total_time, self.total_time, self.total_time)
62 }
63
64 fn build_report_recurse(&self, total_global_time: Duration, avg_global_time: Duration, total_parent_time: Duration, _avg_parent_time: Duration) -> BlockStatReport {
65 let avg_time = match self.measure_count > 0 {
66 true => self.total_time / self.measure_count,
67 false => self.total_time,
68 };
69
70 BlockStatReport {
71 name: {
72 let mut name = String::with_capacity(self.name.len());
73 let mut name_parts_iter = self.name.split("::");
74 while let Some(first_name_part) = name_parts_iter.next() {
75 match name_parts_iter.clone().next() {
76 Some(second_name_part) => {
77 let first_name_part_simplified = first_name_part.to_lowercase().replace("_", "");
78 let second_name_part_simplified = second_name_part.to_lowercase().replace("_", "");
79
80 match first_name_part_simplified == second_name_part_simplified {
81 true => {
82 name += "::";
83 name += second_name_part;
84 name_parts_iter.next();
85 }
86 false => {
87 name += "::";
88 name += first_name_part;
89 }
90 }
91 }
92 None => {
93 name += "::";
94 name += first_name_part;
95 }
96 }
97 }
98
99 name.strip_prefix("::").map(|a| a.to_owned()).unwrap_or(name)
100 },
101 avg_time,
102 global_percents: (self.total_time.as_secs_f32() / total_global_time.as_secs_f32())*100.0,
103 relative_parent_percents: (self.total_time.as_secs_f32() / total_parent_time.as_secs_f32())*100.0,
104 children: {
105 let total_parent_time: Duration = self.total_time;
106 let avg_parent_time: Duration = avg_time;
107 self.children.iter().map(|(_, stat)|
108 stat.build_report_recurse(total_global_time, avg_global_time, total_parent_time, avg_parent_time)
109 ).collect()
110 },
111 }
112 }
113}