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(1, Ordering::Relaxed);
70 let indent = compute_indent(indent_amount);
71
72 $crate::perf_trace::println!("{}{:8} {}", indent, start_info, msg);
73 $crate::perf_trace::TimerInfo {
74 msg: msg.to_string(),
75 time: Instant::now(),
76 }
77 }};
78 }
79
80 #[macro_export]
81 macro_rules! end_timer {
82 ($time:expr) => {{
83 end_timer!($time, || "");
84 }};
85 ($time:expr, $msg:expr) => {{
86 use $crate::perf_trace::inner::{
87 compute_indent, format, AtomicUsize, Colorize, Instant, Ordering, ToString,
88 NUM_INDENT, PAD_CHAR,
89 };
90
91 let time = $time.time;
92 let final_time = time.elapsed();
93 let final_time = {
94 let secs = final_time.as_secs();
95 let millis = final_time.subsec_millis();
96 let micros = final_time.subsec_micros() % 1000;
97 let nanos = final_time.subsec_nanos() % 1000;
98 if secs != 0 {
99 format!("{}.{:03}s", secs, millis).bold()
100 } else if millis > 0 {
101 format!("{}.{:03}ms", millis, micros).bold()
102 } else if micros > 0 {
103 format!("{}.{:03}µs", micros, nanos).bold()
104 } else {
105 format!("{}ns", final_time.subsec_nanos()).bold()
106 }
107 };
108
109 let end_info = "End:".green().bold();
110 let message = format!("{} {}", $time.msg, $msg());
111
112 let indent_amount = 2 * NUM_INDENT.fetch_sub(1, Ordering::Relaxed);
113 let indent = compute_indent(indent_amount);
114
115 $crate::perf_trace::println!(
118 "{}{:8} {:.<pad$}{}",
119 indent,
120 end_info,
121 message,
122 final_time,
123 pad = 75 - indent_amount
124 );
125 }};
126 }
127
128 #[macro_export]
129 macro_rules! add_to_trace {
130 ($title:expr, $msg:expr) => {{
131 use $crate::perf_trace::{
132 compute_indent, compute_indent_whitespace, format, AtomicUsize, Colorize, Instant,
133 Ordering, ToString, NUM_INDENT, PAD_CHAR,
134 };
135
136 let start_msg = "StartMsg".yellow().bold();
137 let end_msg = "EndMsg".green().bold();
138 let title = $title();
139 let start_msg = format!("{}: {}", start_msg, title);
140 let end_msg = format!("{}: {}", end_msg, title);
141
142 let start_indent_amount = 2 * NUM_INDENT.fetch_add(0, Ordering::Relaxed);
143 let start_indent = compute_indent(start_indent_amount);
144
145 let msg_indent_amount = start_indent_amount + 2;
146 let msg_indent = compute_indent_whitespace(msg_indent_amount);
147 let mut final_message = "\n".to_string();
148 for line in $msg().lines() {
149 final_message += &format!("{}{}\n", msg_indent, line,);
150 }
151
152 $crate::perf_trace::println!("{}{}", start_indent, start_msg);
155 $crate::perf_trace::println!("{}{}", msg_indent, final_message,);
156 $crate::perf_trace::println!("{}{}", start_indent, end_msg);
157 }};
158 }
159
160 pub fn compute_indent_whitespace(indent_amount: usize) -> String {
161 let mut indent = String::new();
162 for _ in 0..indent_amount {
163 indent.push_str(" ");
164 }
165 indent
166 }
167
168 pub fn compute_indent(indent_amount: usize) -> String {
169 let mut indent = String::new();
170 for _ in 0..indent_amount {
171 indent.push_str(&PAD_CHAR.white());
172 }
173 indent
174 }
175}
176
177#[macro_use]
178#[cfg(not(feature = "print-trace"))]
179mod inner {
180 pub struct TimerInfo;
181
182 #[macro_export]
183 macro_rules! start_timer {
184 ($msg:expr) => {{
185 let _ = $msg;
186 $crate::perf_trace::TimerInfo
187 }};
188 }
189 #[macro_export]
190 macro_rules! add_to_trace {
191 ($title:expr, $msg:expr) => {
192 let _ = $msg;
193 let _ = $title;
194 };
195 }
196
197 #[macro_export]
198 macro_rules! end_timer {
199 ($time:expr, $msg:expr) => {
200 let _ = $msg;
201 let _ = $time;
202 };
203 ($time:expr) => {
204 let _ = $time;
205 };
206 }
207}
208
209mod tests {
210 use super::*;
211
212 #[test]
213 fn print_start_end() {
214 let start = start_timer!(|| "Hello");
215 end_timer!(start);
216 }
217
218 #[test]
219 fn print_add() {
220 let start = start_timer!(|| "Hello");
221 add_to_trace!(|| "HelloMsg", || "Hello, I\nAm\nA\nMessage");
222 end_timer!(start);
223 }
224}