104 lines
2.3 KiB
Rust
104 lines
2.3 KiB
Rust
use std::sync::{Arc, Mutex};
|
|
|
|
use bounded_vec_deque::BoundedVecDeque;
|
|
use instant::Instant;
|
|
use lazy_static::lazy_static;
|
|
|
|
lazy_static! {
|
|
static ref TRACES: Arc<Mutex<Traces>> = Arc::new(Mutex::new(Traces::new()));
|
|
}
|
|
|
|
const MAX_BUFFER_SIZE: usize = 1024;
|
|
|
|
struct Traces {
|
|
// Bounded in case we are tracing a lot of events and we don't want to blow
|
|
// up memory
|
|
events: BoundedVecDeque<TraceEvent>,
|
|
end_after_next: Option<&'static str>,
|
|
}
|
|
|
|
impl Traces {
|
|
fn new() -> Self {
|
|
Self {
|
|
events: BoundedVecDeque::new(MAX_BUFFER_SIZE),
|
|
end_after_next: None,
|
|
}
|
|
}
|
|
}
|
|
|
|
struct TraceEvent {
|
|
timestamp: Instant,
|
|
name: &'static str,
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! start_trace {
|
|
($name:expr) => {
|
|
#[cfg(feature = "traces")]
|
|
$crate::traces::start_trace($name)
|
|
};
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! record_trace_event {
|
|
($name:expr) => {
|
|
#[cfg(feature = "traces")]
|
|
$crate::traces::record_event($name)
|
|
};
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! end_trace_after_next {
|
|
($name:expr) => {
|
|
#[cfg(feature = "traces")]
|
|
$crate::traces::end_trace_after_next($name)
|
|
};
|
|
}
|
|
|
|
#[macro_export]
|
|
macro_rules! end_trace {
|
|
() => {
|
|
#[cfg(feature = "traces")]
|
|
$crate::traces::end_trace()
|
|
};
|
|
}
|
|
|
|
pub fn start_trace(event_name: &'static str) {
|
|
TRACES.lock().unwrap().events.clear();
|
|
record_event(event_name);
|
|
}
|
|
|
|
pub fn record_event(name: &'static str) {
|
|
let should_end = {
|
|
// Separate block to let the mutex go out of scope before calling end_trace
|
|
let mut traces = TRACES.lock().unwrap();
|
|
traces.events.push_back(TraceEvent {
|
|
name,
|
|
timestamp: Instant::now(),
|
|
});
|
|
|
|
traces.end_after_next == Some(name)
|
|
};
|
|
if should_end {
|
|
end_trace();
|
|
}
|
|
}
|
|
|
|
pub fn end_trace_after_next(event_name: &'static str) {
|
|
TRACES.lock().unwrap().end_after_next = Some(event_name);
|
|
}
|
|
|
|
pub fn end_trace() {
|
|
let mut traces = TRACES.lock().unwrap();
|
|
let start = traces.events.pop_front().expect("no empty traces");
|
|
for event in traces.events.iter() {
|
|
println!(
|
|
"[{:.4} ms] {} ",
|
|
(event.timestamp.duration_since(start.timestamp).as_micros() as f32 / 1000.),
|
|
event.name,
|
|
);
|
|
}
|
|
traces.end_after_next = None;
|
|
traces.events.clear();
|
|
}
|