1use crate::error;
4
5struct StopwatchTime {
6 now: std::time::SystemTime,
7 self_user: std::time::Duration,
8 self_system: std::time::Duration,
9 children_user: std::time::Duration,
10 children_system: std::time::Duration,
11}
12
13impl StopwatchTime {
14 #[allow(clippy::unchecked_time_subtraction)]
15 fn minus(&self, other: &Self) -> Result<StopwatchTiming, error::Error> {
16 let user = (self.self_user - other.self_user) + (self.children_user - other.children_user);
17 let system =
18 (self.self_system - other.self_system) + (self.children_system - other.children_system);
19
20 Ok(StopwatchTiming {
21 wall: self.now.duration_since(other.now)?,
22 user,
23 system,
24 })
25 }
26}
27
28pub(crate) struct Stopwatch {
29 start: StopwatchTime,
30}
31
32impl Stopwatch {
33 pub fn stop(&self) -> Result<StopwatchTiming, error::Error> {
41 let end = get_current_stopwatch_time()?;
42 end.minus(&self.start)
43 }
44}
45pub(crate) struct StopwatchTiming {
46 pub wall: std::time::Duration,
47 pub user: std::time::Duration,
48 pub system: std::time::Duration,
49}
50
51pub(crate) fn start_timing() -> Result<Stopwatch, error::Error> {
52 Ok(Stopwatch {
53 start: get_current_stopwatch_time()?,
54 })
55}
56
57fn get_current_stopwatch_time() -> Result<StopwatchTime, error::Error> {
58 let now = std::time::SystemTime::now();
59 let (self_user, self_system) = crate::sys::resource::get_self_user_and_system_time()?;
60 let (children_user, children_system) =
61 crate::sys::resource::get_children_user_and_system_time()?;
62
63 Ok(StopwatchTime {
64 now,
65 self_user,
66 self_system,
67 children_user,
68 children_system,
69 })
70}
71
72pub fn format_duration_non_posixly(duration: &std::time::Duration) -> String {
78 let minutes = duration.as_secs() / 60;
79 let seconds = duration.as_secs() % 60;
80 let millis = duration.subsec_millis();
81 format!("{minutes}m{seconds}.{millis:03}s")
82}
83
84pub fn format_duration_posixly(duration: &std::time::Duration) -> String {
90 let seconds = duration.as_secs();
91 let ten_millis = duration.subsec_millis() / 10;
92 format!("{seconds}.{ten_millis:02}")
93}
94
95#[cfg(test)]
96mod tests {
97 use std::time::Duration;
98
99 use super::*;
100
101 #[test]
102 fn test_format_time() {
103 assert_eq!(
104 format_duration_non_posixly(&Duration::from_millis(0)),
105 "0m0.000s"
106 );
107 assert_eq!(
108 format_duration_non_posixly(&Duration::from_millis(1)),
109 "0m0.001s"
110 );
111 assert_eq!(
112 format_duration_non_posixly(&Duration::from_millis(123)),
113 "0m0.123s"
114 );
115 assert_eq!(
116 format_duration_non_posixly(&Duration::from_millis(1234)),
117 "0m1.234s"
118 );
119 assert_eq!(
120 format_duration_non_posixly(&Duration::from_millis(12345)),
121 "0m12.345s"
122 );
123 assert_eq!(
124 format_duration_non_posixly(&Duration::from_millis(123_456)),
125 "2m3.456s"
126 );
127 assert_eq!(
128 format_duration_non_posixly(&Duration::from_millis(1_234_567)),
129 "20m34.567s"
130 );
131
132 assert_eq!(
133 format_duration_non_posixly(&Duration::from_micros(1)),
134 "0m0.000s"
135 );
136 assert_eq!(
137 format_duration_non_posixly(&Duration::from_micros(999)),
138 "0m0.000s"
139 );
140 assert_eq!(
141 format_duration_non_posixly(&Duration::from_micros(1001)),
142 "0m0.001s"
143 );
144 }
145}