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> {
34 let end = get_current_stopwatch_time()?;
35 end.minus(&self.start)
36 }
37}
38pub(crate) struct StopwatchTiming {
39 pub wall: std::time::Duration,
40 pub user: std::time::Duration,
41 pub system: std::time::Duration,
42}
43
44pub(crate) fn start_timing() -> Result<Stopwatch, error::Error> {
45 Ok(Stopwatch {
46 start: get_current_stopwatch_time()?,
47 })
48}
49
50fn get_current_stopwatch_time() -> Result<StopwatchTime, error::Error> {
51 let now = std::time::SystemTime::now();
52 let (self_user, self_system) = crate::sys::resource::get_self_user_and_system_time()?;
53 let (children_user, children_system) =
54 crate::sys::resource::get_children_user_and_system_time()?;
55
56 Ok(StopwatchTime {
57 now,
58 self_user,
59 self_system,
60 children_user,
61 children_system,
62 })
63}
64
65pub fn format_duration_non_posixly(duration: &std::time::Duration) -> String {
71 let minutes = duration.as_secs() / 60;
72 let seconds = duration.as_secs() % 60;
73 let millis = duration.subsec_millis();
74 format!("{minutes}m{seconds}.{millis:03}s")
75}
76
77pub fn format_duration_posixly(duration: &std::time::Duration) -> String {
83 let seconds = duration.as_secs();
84 let ten_millis = duration.subsec_millis() / 10;
85 format!("{seconds}.{ten_millis:02}")
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use std::time::Duration;
92
93 #[test]
94 fn test_format_time() {
95 assert_eq!(
96 format_duration_non_posixly(&Duration::from_millis(0)),
97 "0m0.000s"
98 );
99 assert_eq!(
100 format_duration_non_posixly(&Duration::from_millis(1)),
101 "0m0.001s"
102 );
103 assert_eq!(
104 format_duration_non_posixly(&Duration::from_millis(123)),
105 "0m0.123s"
106 );
107 assert_eq!(
108 format_duration_non_posixly(&Duration::from_millis(1234)),
109 "0m1.234s"
110 );
111 assert_eq!(
112 format_duration_non_posixly(&Duration::from_millis(12345)),
113 "0m12.345s"
114 );
115 assert_eq!(
116 format_duration_non_posixly(&Duration::from_millis(123_456)),
117 "2m3.456s"
118 );
119 assert_eq!(
120 format_duration_non_posixly(&Duration::from_millis(1_234_567)),
121 "20m34.567s"
122 );
123
124 assert_eq!(
125 format_duration_non_posixly(&Duration::from_micros(1)),
126 "0m0.000s"
127 );
128 assert_eq!(
129 format_duration_non_posixly(&Duration::from_micros(999)),
130 "0m0.000s"
131 );
132 assert_eq!(
133 format_duration_non_posixly(&Duration::from_micros(1000)),
134 "0m0.001s"
135 );
136 }
137}