timeit/
lib.rs

1//! This crate provides macros that make it easy to benchmark blocks of code. It is inspired and
2//! named after timeit from Python.
3//!
4//! Example:
5//!
6//! ```
7//! #[macro_use]
8//! extern crate timeit;
9//!
10//! fn main() {
11//!     timeit!({
12//!         let mut x: Vec<u64> = Vec::new();
13//!         for i in 0..1000 {
14//!             x.push(i);
15//!         }
16//!     });
17//! }
18//! ```
19//!
20//! This will output something like:
21//!
22//! ```text
23//! 10000 loops: 2.4843 µs
24//! ```
25//!
26//! It will determine the number of loops automatically. To run a specified number of loops and
27//! save the elapsed time to a variable, use the `timeit_loops!` macro:
28//!
29//! ```
30//! let sec = timeit_loops!(100, {
31//!     let mut x: Vec<u64> = Vec::new();
32//!     for i in 0..1000 {
33//!         x.push(i);
34//!     }
35//! });
36//! ```
37extern crate time;
38
39use time::Timespec;
40
41/// A shortcut to time's `get_time` function. This is so that the user of timeit doesn't have to
42/// separately add a dependency for the time crate.
43pub fn get_time() -> Timespec {
44    use time::get_time;
45    get_time()
46}
47
48#[macro_export]
49/// Runs a block a specified number of times and returns the average time of execution.
50macro_rules! timeit_loops {
51    ($loops:expr, $code:block) => ({
52        use timeit::get_time;
53
54        let n = $loops;
55        let start = get_time();
56        for _ in 0..n {
57            $code
58        }
59        let end = get_time();
60        let sec = (end.sec - start.sec) as f64 +
61                  (end.nsec - start.nsec) as f64 / 1_000_000_000.0;
62
63        sec / (n as f64)
64    })
65}
66
67#[macro_export]
68/// Runs a block several times and outputs the average time per loop. The number of loops is
69/// determined automatically.
70macro_rules! timeit {
71    ($code:block) => ({
72        let mut n = 1;
73        let mut sec = timeit_loops!(n, $code);
74        let mut again = true;
75
76        let l = sec.log10().ceil() as isize;
77
78        if l < -5 {
79            n = 1000_000;
80        } else if l <= 0 {
81            n = 10isize.pow((-l) as u32);
82        } else {
83            again = false;
84        }
85
86        if again {
87            sec = timeit_loops!(n, $code);
88        }
89
90        let (mult, unit_str) = if sec > 1.0 {
91            (1.0, "s")
92        } else if sec > 0.001 {
93            (0.001, "ms")
94        } else if sec > 0.000_001 {
95            (0.000_001, "µs")
96        } else {
97            (0.000_000_001, "ns")
98        };
99
100        println!("{} loops: {} {}", n, sec / mult, unit_str);
101    })
102}