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}