1#![allow(unused_imports)]
2pub use self::inner::*;
37
38#[macro_use]
39#[cfg(feature = "print-trace")]
40pub mod inner {
41 pub use colored::Colorize;
42
43 pub use std::{
45 format, println,
46 string::{String, ToString},
47 sync::atomic::{AtomicUsize, Ordering},
48 time::Instant,
49 };
50
51 pub static NUM_INDENT: AtomicUsize = AtomicUsize::new(0);
52 pub const PAD_CHAR: &str = "·";
53
54 pub struct TimerInfo {
55 pub msg: String,
56 pub time: Instant,
57 }
58
59 #[macro_export]
60 macro_rules! start_timer {
61 ($msg:expr) => {{
62 use $crate::perf_trace::inner::{
63 compute_indent, AtomicUsize, Colorize, Instant, Ordering, ToString, NUM_INDENT,
64 PAD_CHAR,
65 };
66
67 let msg = $msg();
68 let start_info = "Start:".yellow().bold();
69 let indent_amount = 2 * NUM_INDENT.fetch_add(0, Ordering::Relaxed);
70 let indent = compute_indent(indent_amount);
71
72 $crate::perf_trace::println!("{}{:8} {}", indent, start_info, msg);
73 NUM_INDENT.fetch_add(1, Ordering::Relaxed);
74 $crate::perf_trace::TimerInfo {
75 msg: msg.to_string(),
76 time: Instant::now(),
77 }
78 }};
79 }
80
81 #[macro_export]
82 macro_rules! end_timer {
83 ($time:expr) => {{
84 end_timer!($time, || "");
85 }};
86 ($time:expr, $msg:expr) => {{
87 use $crate::perf_trace::inner::{
88 compute_indent, format, AtomicUsize, Colorize, Instant, Ordering, ToString,
89 NUM_INDENT, PAD_CHAR,
90 };
91
92 let time = $time.time;
93 let final_time = time.elapsed();
94 let final_time = {
95 let secs = final_time.as_secs();
96 let millis = final_time.subsec_millis();
97 let micros = final_time.subsec_micros() % 1000;
98 let nanos = final_time.subsec_nanos() % 1000;
99 if secs != 0 {
100 format!("{}.{:03}s", secs, millis).bold()
101 } else if millis > 0 {
102 format!("{}.{:03}ms", millis, micros).bold()
103 } else if micros > 0 {
104 format!("{}.{:03}µs", micros, nanos).bold()
105 } else {
106 format!("{}ns", final_time.subsec_nanos()).bold()
107 }
108 };
109
110 let end_info = "End:".green().bold();
111 let message = format!("{} {}", $time.msg, $msg());
112
113 NUM_INDENT.fetch_sub(1, Ordering::Relaxed);
114 let indent_amount = 2 * NUM_INDENT.fetch_add(0, Ordering::Relaxed);
115 let indent = compute_indent(indent_amount);
116
117 $crate::perf_trace::println!(
120 "{}{:8} {:.<pad$}{}",
121 indent,
122 end_info,
123 message,
124 final_time,
125 pad = 75 - indent_amount
126 );
127 }};
128 }
129
130 #[macro_export]
131 macro_rules! add_to_trace {
132 ($title:expr, $msg:expr) => {{
133 use $crate::perf_trace::{
134 compute_indent, compute_indent_whitespace, format, AtomicUsize, Colorize, Instant,
135 Ordering, ToString, NUM_INDENT, PAD_CHAR,
136 };
137
138 let start_msg = "StartMsg".yellow().bold();
139 let end_msg = "EndMsg".green().bold();
140 let title = $title();
141 let start_msg = format!("{}: {}", start_msg, title);
142 let end_msg = format!("{}: {}", end_msg, title);
143
144 let start_indent_amount = 2 * NUM_INDENT.fetch_add(0, Ordering::Relaxed);
145 let start_indent = compute_indent(start_indent_amount);
146
147 let msg_indent_amount = 2 * NUM_INDENT.fetch_add(0, Ordering::Relaxed) + 2;
148 let msg_indent = compute_indent_whitespace(msg_indent_amount);
149 let mut final_message = "\n".to_string();
150 for line in $msg().lines() {
151 final_message += &format!("{}{}\n", msg_indent, line,);
152 }
153
154 $crate::perf_trace::println!("{}{}", start_indent, start_msg);
157 $crate::perf_trace::println!("{}{}", msg_indent, final_message,);
158 $crate::perf_trace::println!("{}{}", start_indent, end_msg);
159 }};
160 }
161
162 #[macro_export]
163 macro_rules! add_single_trace {
164 ($title:expr) => {{
165 use $crate::perf_trace::{
166 compute_indent, compute_indent_whitespace, format, AtomicUsize, Colorize, Instant,
167 Ordering, ToString, NUM_INDENT, PAD_CHAR,
168 };
169
170 let start_msg = "Trace".blue().bold();
171 let title = $title();
172 let start_msg = format!("{}: {}", start_msg, title);
173
174 let indent_amount = 2 * NUM_INDENT.fetch_add(0, Ordering::Relaxed);
175 let indent = compute_indent(indent_amount);
176
177 $crate::perf_trace::println!("{}{}", indent, start_msg);
180 }};
181 }
182
183 pub fn compute_indent_whitespace(indent_amount: usize) -> String {
184 let mut indent = String::new();
185 for _ in 0..indent_amount {
186 indent.push_str(" ");
187 }
188 indent
189 }
190
191 pub fn compute_indent(indent_amount: usize) -> String {
192 let mut indent = String::new();
193 for _ in 0..indent_amount {
194 indent.push_str(&PAD_CHAR.white());
195 }
196 indent
197 }
198}
199
200#[macro_use]
201#[cfg(not(feature = "print-trace"))]
202mod inner {
203 pub struct TimerInfo;
204
205 #[macro_export]
206 macro_rules! start_timer {
207 ($msg:expr) => {{
208 let _ = $msg;
209 $crate::perf_trace::TimerInfo
210 }};
211 }
212 #[macro_export]
213 macro_rules! add_to_trace {
214 ($title:expr, $msg:expr) => {
215 let _ = $msg;
216 let _ = $title;
217 };
218 }
219 #[macro_export]
220 macro_rules! add_single_trace {
221 ($msg:expr) => {{
222 let _ = $msg;
223 $crate::perf_trace::TimerInfo
224 }};
225 }
226 #[macro_export]
227 macro_rules! end_timer {
228 ($time:expr, $msg:expr) => {
229 let _ = $msg;
230 let _ = $time;
231 };
232 ($time:expr) => {
233 let _ = $time;
234 };
235 }
236}
237
238mod tests {
239 use super::*;
240
241 #[test]
242 fn print_start_end() {
243 let start = start_timer!(|| "Hello");
244 end_timer!(start);
245 }
246
247 #[test]
248 fn print_add() {
249 add_single_trace!(|| "Hello");
250 let start = start_timer!(|| "Hello");
251 add_single_trace!(|| "HelloWorld");
252 add_to_trace!(|| "HelloMsg", || "Hello, I\nAm\nA\nMessage");
253 end_timer!(start);
254 }
255}