solana_measure/
macros.rs

1/// Measure this expression
2///
3/// Use `measure_time!()` when you have an expression that you want to measure.  `measure_time!()` will start
4/// a new [`Measure`], evaluate your expression, stop the [`Measure`], and then return the
5/// [`Measure`] object along with your expression's return value.
6///
7/// Use `measure_us!()` when you want to measure an expression in microseconds.
8///
9/// Use `meas_dur!()` when you want to measure an expression and get the Duration.
10///
11/// [`Measure`]: crate::measure::Measure
12///
13/// # Examples
14///
15/// ```
16/// // Measure functions
17/// # use solana_measure::{measure_time, measure_us, meas_dur};
18/// # fn foo() {}
19/// # fn bar(x: i32) {}
20/// # fn add(x: i32, y: i32) -> i32 {x + y}
21/// let (result, measure) = measure_time!(foo(), "foo takes no parameters");
22/// let (result, measure) = measure_time!(bar(42), "bar takes one parameter");
23/// let (result, measure) = measure_time!(add(1, 2), "add takes two parameters and returns a value");
24/// let (result, measure_us) = measure_us!(add(1, 2));
25/// let (result, duration) = meas_dur!(add(1, 2));
26/// # assert_eq!(result, 1 + 2);
27/// ```
28///
29/// ```
30/// // Measure methods
31/// # use solana_measure::{measure_time, measure_us, meas_dur};
32/// # struct Foo {
33/// #     f: i32,
34/// # }
35/// # impl Foo {
36/// #     fn frobnicate(&self, bar: i32) -> i32 {
37/// #         self.f * bar
38/// #     }
39/// # }
40/// let foo = Foo { f: 42 };
41/// let (result, measure) = measure_time!(foo.frobnicate(2), "measure methods");
42/// let (result, measure_us) = measure_us!(foo.frobnicate(2));
43/// let (result, duration) = meas_dur!(foo.frobnicate(2));
44/// # assert_eq!(result, 42 * 2);
45/// ```
46///
47/// ```
48/// // Measure expression blocks
49/// # use solana_measure::measure_time;
50/// # fn complex_calculation() -> i32 { 42 }
51/// # fn complex_transform(x: i32) -> i32 { x + 3 }
52/// # fn record_result(y: i32) {}
53/// let (result, measure) = measure_time!(
54///     {
55///         let x = complex_calculation();
56///         # assert_eq!(x, 42);
57///         let y = complex_transform(x);
58///         # assert_eq!(y, 42 + 3);
59///         record_result(y);
60///         y
61///     },
62///     "measure a block of many operations",
63/// );
64/// # assert_eq!(result, 42 + 3);
65/// ```
66///
67/// ```
68/// // The `name` parameter is optional
69/// # use solana_measure::{measure_time, measure_us};
70/// # fn meow() {};
71/// let (result, measure) = measure_time!(meow());
72/// let (result, measure_us) = measure_us!(meow());
73/// ```
74#[macro_export]
75macro_rules! measure_time {
76    ($val:expr, $name:tt $(,)?) => {{
77        let mut measure = $crate::measure::Measure::start($name);
78        let result = $val;
79        measure.stop();
80        (result, measure)
81    }};
82    ($val:expr) => {
83        measure_time!($val, "")
84    };
85}
86
87#[macro_export]
88macro_rules! measure_us {
89    ($expr:expr) => {{
90        let (result, duration) = $crate::meas_dur!($expr);
91        (result, duration.as_micros() as u64)
92    }};
93}
94
95/// Measures how long it takes to execute an expression, and returns a Duration
96///
97/// # Examples
98///
99/// ```
100/// # use solana_measure::meas_dur;
101/// # fn meow(x: i32, y: i32) -> i32 {x + y}
102/// let (result, duration) = meas_dur!(meow(1, 2) + 3);
103/// # assert_eq!(result, 1 + 2 + 3);
104/// ```
105//
106// The macro name, `meas_dur`, is "measure" + "duration".
107// When said aloud, the pronunciation is close to "measure".
108#[macro_export]
109macro_rules! meas_dur {
110    ($expr:expr) => {{
111        let start = std::time::Instant::now();
112        let result = $expr;
113        (result, start.elapsed())
114    }};
115}
116
117#[cfg(test)]
118mod tests {
119    use std::{thread::sleep, time::Duration};
120
121    fn my_multiply(x: i32, y: i32) -> i32 {
122        x * y
123    }
124
125    fn square(x: i32) -> i32 {
126        my_multiply(x, x)
127    }
128
129    struct SomeStruct {
130        x: i32,
131    }
132    impl SomeStruct {
133        fn add_to(&self, x: i32) -> i32 {
134            x + self.x
135        }
136    }
137
138    #[test]
139    fn test_measure_macro() {
140        // Ensure that the measurement side actually works
141        {
142            let (_result, measure) = measure_time!(sleep(Duration::from_millis(1)), "test");
143            assert!(measure.as_s() > 0.0);
144            assert!(measure.as_ms() > 0);
145            assert!(measure.as_us() > 0);
146        }
147
148        // Ensure that the macro can be called with functions
149        {
150            let (result, _measure) = measure_time!(my_multiply(3, 4), "test");
151            assert_eq!(result, 3 * 4);
152
153            let (result, _measure) = measure_time!(square(5), "test");
154            assert_eq!(result, 5 * 5)
155        }
156
157        // Ensure that the macro can be called with methods
158        {
159            let some_struct = SomeStruct { x: 42 };
160            let (result, _measure) = measure_time!(some_struct.add_to(4), "test");
161            assert_eq!(result, 42 + 4);
162        }
163
164        // Ensure that the macro can be called with blocks
165        {
166            let (result, _measure) = measure_time!({ 1 + 2 }, "test");
167            assert_eq!(result, 3);
168        }
169
170        // Ensure that the macro can be called with a trailing comma
171        {
172            let (result, _measure) = measure_time!(square(5), "test",);
173            assert_eq!(result, 5 * 5)
174        }
175
176        // Ensure that the macro can be called without a name
177        {
178            let (result, _measure) = measure_time!(square(5));
179            assert_eq!(result, 5 * 5)
180        }
181    }
182
183    #[test]
184    fn test_measure_us_macro() {
185        // Ensure that the measurement side actually works
186        {
187            let (_result, measure) = measure_us!(sleep(Duration::from_millis(1)));
188            assert!(measure > 0);
189        }
190
191        // Ensure that the macro can be called with functions
192        {
193            let (result, _measure) = measure_us!(my_multiply(3, 4));
194            assert_eq!(result, 3 * 4);
195
196            let (result, _measure) = measure_us!(square(5));
197            assert_eq!(result, 5 * 5)
198        }
199
200        // Ensure that the macro can be called with methods
201        {
202            let some_struct = SomeStruct { x: 42 };
203            let (result, _measure) = measure_us!(some_struct.add_to(4));
204            assert_eq!(result, 42 + 4);
205        }
206
207        // Ensure that the macro can be called with blocks
208        {
209            let (result, _measure) = measure_us!({ 1 + 2 });
210            assert_eq!(result, 3);
211        }
212    }
213
214    #[test]
215    fn test_meas_dur_macro() {
216        // Ensure that the macro can be called with functions
217        {
218            let (result, _duration) = meas_dur!(my_multiply(3, 4));
219            assert_eq!(result, 3 * 4);
220
221            let (result, _duration) = meas_dur!(square(5));
222            assert_eq!(result, 5 * 5)
223        }
224
225        // Ensure that the macro can be called with methods
226        {
227            let some_struct = SomeStruct { x: 42 };
228            let (result, _duration) = meas_dur!(some_struct.add_to(4));
229            assert_eq!(result, 42 + 4);
230        }
231
232        // Ensure that the macro can be called with blocks
233        {
234            let (result, _duration) = meas_dur!({ 1 + 2 });
235            assert_eq!(result, 3);
236        }
237    }
238}