//! Simple hierarchical profiler use once_cell::sync::Lazy; use std::{ cell::RefCell, collections::{BTreeMap, HashSet}, io::{stderr, Write}, sync::{ atomic::{AtomicBool, Ordering}, RwLock, }, time::{Duration, Instant}, }; use crate::tree::{Idx, Tree}; /// Filtering syntax /// env RA_PROFILE=* // dump everything /// env RA_PROFILE=foo|bar|baz // enabled only selected entries /// env RA_PROFILE=*@3>10 // dump everything, up to depth 3, if it takes more than 10 ms pub fn init() { let spec = std::env::var("RA_PROFILE").unwrap_or_default(); init_from(&spec); } pub fn init_from(spec: &str) { let filter = if spec.is_empty() { Filter::disabled() } else { Filter::from_spec(spec) }; filter.install(); } pub type Label = &'static str; /// This function starts a profiling scope in the current execution stack with a given description. /// It returns a Profile structure and measure elapsed time between this method invocation and Profile structure drop. /// It supports nested profiling scopes in case when this function invoked multiple times at the execution stack. In this case the profiling information will be nested at the output. /// Profiling information is being printed in the stderr. /// /// # Example /// ``` /// use ra_prof::{profile, set_filter, Filter}; /// /// let f = Filter::from_spec("profile1|profile2@2"); /// set_filter(f); /// profiling_function1(); /// /// fn profiling_function1() { /// let _p = profile("profile1"); /// profiling_function2(); /// } /// /// fn profiling_function2() { /// let _p = profile("profile2"); /// } /// ``` /// This will print in the stderr the following: /// ```text /// 0ms - profile /// 0ms - profile2 /// ``` pub fn profile(label: Label) -> Profiler { assert!(!label.is_empty()); let enabled = PROFILING_ENABLED.load(Ordering::Relaxed) && PROFILE_STACK.with(|stack| stack.borrow_mut().push(label)); let label = if enabled { Some(label) } else { None }; Profiler { label, detail: None } } pub struct Profiler { label: Option