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}