time_elapsed/lib.rs
1//! A Rust crate that provides a concise and handy way to benchmark **elapsed time inside functions**.
2//! > time-elapsed brings a small overhead, however, if you are trying to measure very small durations (in the order of *nanoseconds* or few *microseconds*), please consider using something else.
3//!
4//! ### installation
5//! Add the following to Cargo.toml
6//! ```
7//! [dependencies]
8//! time-elapsed = "0.1.0"
9//! ```
10//!
11//! # features
12//! * named benchmark
13//! * timestamps
14//! * coloured messages
15//! * auto unit of measurement
16//!
17//! # example
18//!
19//! ### code
20//!
21//! ```
22//! use std::thread;
23//! use std::time::Duration;
24//!
25//! use time_elapsed;
26//!
27//! fn main() {
28//! let mut time = time_elapsed::start("test");
29//!
30//! // sleep 200 ms
31//! thread::sleep(Duration::from_millis(200));
32//!
33//! time
34//! .log("log() prints a message and the time elapsed")
35//! .timestamp();
36//!
37//! // sleep 2 ms
38//! thread::sleep(Duration::from_millis(2));
39//!
40//! time.log("this is an offset from the previous timestamp()");
41//!
42//! time.log_overall("log_overall() ignores timestamps");
43//!
44//! time.end();
45//! }
46//! ```
47//!
48//! ### output
49//!
50//! ```console
51//! running test...
52//! (test) log() prints a message and the time elapsed -> 200ms
53//! (test) this is an offset from the previous timestamp() -> 2103 μs
54//! (test) log_overall() ignores timestamps -> 202 ms
55//! test finished in 202 ms (202271 μs)
56//! ```
57//!
58
59use std::time::Instant;
60
61/// Starts the benchmark by returning an initialized instance of **TimeElpased**.
62///
63/// # example
64///
65/// ```
66/// let mut time = time_elapsed::start("test");
67/// // output: running test...
68/// ```
69pub fn start<S: AsRef<str>>(name: S) -> TimeElapsed {
70 TimeElapsed::new(name.as_ref())
71}
72
73fn get_unit_of_measurement(nanos: u128) -> &'static str {
74 match nanos / 4000000 {
75 0 => "μs",
76 _ => match nanos / 15000000000 {
77 0 => "ms",
78 _ => match nanos / 300000000000 {
79 0 => "s",
80 _ => match nanos / 540000000000 {
81 0 => "min",
82 _ => "hrs",
83 },
84 },
85 },
86 }
87}
88
89fn get_units_of_measurement(nanos: u128) -> [&'static str; 2] {
90 match get_unit_of_measurement(nanos) {
91 "μs" => ["μs", "ns"],
92 "ms" => ["ms", "μs"],
93 "s" => ["s", "ms"],
94 "min" => ["min", "s"],
95 "hrs" => ["hrs", "min"],
96 _ => ["ns", "ns"],
97 }
98}
99
100fn nanos_to_unit_of_msr(nanos: u128, unit_of_msr: &str) -> u128 {
101 match unit_of_msr {
102 "μs" => nanos / 1000,
103 "ms" => nanos / 1000000,
104 "s" => nanos / 1000000000,
105 "min" => nanos / 60000000000,
106 "hrs" => nanos / 3600000000000,
107 _ => nanos,
108 }
109}
110
111fn nanos_to_units_of_msr(nanos: u128, unit_of_msr: &str) -> [u128; 2] {
112 match unit_of_msr {
113 "μs" => [nanos / 1000, nanos],
114 "ms" => [nanos / 1000000, nanos / 1000],
115 "s" => [nanos / 1000000000, nanos / 1000000],
116 "min" => [nanos / 60000000000, nanos / 1000000000],
117 "hrs" => [nanos / 3600000000000, nanos / 60000000000],
118 _ => [nanos, nanos],
119 }
120}
121
122/// Stores the benchmark state and provides methods (timestamp method needs a mutable reference).
123///
124/// To create an initialized instance use the **time_elapsed::start** function.
125///
126/// # example
127///
128/// ```
129/// let mut time = time_elapsed::start("test");
130/// // output: running test...
131///
132/// ```
133#[derive(Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
134pub struct TimeElapsed {
135 name: String,
136 start_timestamp: Instant,
137 last_timestamp: Instant,
138}
139
140impl TimeElapsed {
141
142 fn new(name: &str) -> Self {
143 println!("running {}...", name);
144 Self {
145 name: name.to_string(),
146 start_timestamp: Instant::now(),
147 last_timestamp: Instant::now(),
148 }
149 }
150
151 fn print_message(&mut self, msg: &str, nanos: u128) -> &Self {
152 let unit = get_unit_of_measurement(nanos);
153 let time = nanos_to_unit_of_msr(nanos, unit);
154 println!(
155 "(\x1b[32m\x1b[1m{}\x1b[0m) \x1b[1m{} \x1b[0m-> \x1b[35m\x1b[1m{} {} \x1b[0m",
156 self.name, msg, time, unit
157 );
158 self
159 }
160
161 /// Ends the benchmark. Outputs the total elapsed time from the start
162 /// of the benchmark.
163 ///
164 /// # example
165 ///
166 /// ```
167 /// let mut time = time_elapsed::start("test");
168 /// // output: running test...
169 ///
170 /// time.end();
171 /// // output: test finished in 1 μs (1204 ns)
172 ///
173 /// ```
174 pub fn end(self) {
175 let nanos = self.start_timestamp.elapsed().as_nanos();
176 let units = get_units_of_measurement(nanos);
177 let times = nanos_to_units_of_msr(nanos, units[0]);
178 println!(
179 "\x1b[32m\x1b[1m{} finished\x1b[0m in \x1b[35m\x1b[1m{} {} \x1b[0m({} {})",
180 self.name, times[0], units[0], times[1], units[1],
181 );
182 }
183
184 /// Outputs a message followed by the **elapsed time** from the **previous timestamp**.
185 ///
186 /// Returns a mutable reference of self.
187 ///
188 /// # example
189 ///
190 /// ```
191 /// let mut time = time_elapsed::start("test");
192 /// // output: running test...
193 ///
194 /// time.log("My message");
195 /// // output: (test) My message -> 1 μs
196 ///
197 /// ```
198 pub fn log<S: AsRef<str>>(&mut self, msg: S) -> &mut Self {
199 let nanos = self.last_timestamp.elapsed().as_nanos();
200 self.print_message(msg.as_ref(), nanos);
201 self
202 }
203
204 /// Outputs a message followed by the **elapsed time** from the **start**, ignoring timestamps.
205 ///
206 /// Returns a mutable reference of self.
207 ///
208 /// # example
209 ///
210 /// ```
211 /// use std::thread;
212 /// use std::time::Duration;
213 ///
214 /// let mut time = time_elapsed::start("test");
215 /// // output: running test...
216 ///
217 /// thread::sleep(Duration::from_millis(200));
218 ///
219 /// time.timestamp();
220 /// time.log_overall("The elapsed time from the start");
221 /// // output: (test) The elapsed time from the start -> 200 ms
222 ///
223 /// ```
224 pub fn log_overall<S: AsRef<str>>(&mut self, msg: S) -> &mut Self {
225 let nanos = self.start_timestamp.elapsed().as_nanos();
226 self.print_message(msg.as_ref(), nanos);
227 self
228 }
229
230 /// Updates and returns the last timestamp.
231 ///
232 /// # example
233 ///
234 /// ```
235 /// use std::thread;
236 /// use std::time::Duration;
237 /// let mut time = time_elapsed::start("test");
238 /// // output: running test...
239 ///
240 /// thread::sleep(Duration::from_millis(200));
241 ///
242 /// time.timestamp();
243 ///
244 /// time.log("Elapsed time from the prev timestamp");
245 /// // output: (test) Elapsed time from the prev timestamp -> 1 μs
246 ///
247 /// ```
248 pub fn timestamp(&mut self) -> Instant {
249 self.last_timestamp = Instant::now();
250 self.last_timestamp
251 }
252}