tinyprof 0.0.1

Tiny realtime frame profiler, well used with tinyecs
Documentation
extern crate time;
#[macro_use] extern crate lazy_static;

mod profiler_frame;
mod profiler_state;

use std::sync::Mutex;
use time::precise_time_s;
use std::ops::Drop;

pub use profiler_frame::*;
pub use profiler_state::*;

lazy_static! {
    pub static ref PROFILER_STATE: Mutex<ProfilerState> = Mutex::new(ProfilerState::new());
}

#[derive(Debug)]
pub struct ProfilerReport {
    pub name        : String,
    pub time        : f64,
    pub percent     : f64,
    pub sub_reports : Vec<ProfilerReport>
}

pub fn profiler_report() -> ProfilerReport {
    state_report(&mut *PROFILER_STATE.lock().unwrap())
}
pub fn profiler_next_frame() {
    PROFILER_STATE.lock().unwrap().next_frame();
}

pub struct ProfilerRegion {
    pub enter_time : f64,
    pub name       : String
}
impl ProfilerRegion {
    pub fn new(name : &str) -> ProfilerRegion {
        PROFILER_STATE.lock().unwrap().begin_track_time(name.to_string());
        ProfilerRegion {
            enter_time : precise_time_s(),
            name       : name.to_string()
        }
    }
}
impl Drop for ProfilerRegion {
    fn drop(&mut self) {
        PROFILER_STATE.lock().unwrap().end_track_time(precise_time_s() - self.enter_time);
    }
}


#[macro_export]
macro_rules! profile_region {
    ($name:expr) => {
        let _profile = $crate::ProfilerRegion::new($name);
    }
}

#[macro_export]
macro_rules! print_region_time {
    ($x:expr, $pattern:expr) => {{
        use time::precise_time_s;

        let start = precise_time_s();
        let res = $x;
        let end = precise_time_s();
        println!($pattern, end - start);
        res
    }};
}

pub fn state_report(state : &mut ProfilerState) -> ProfilerReport {
    let frame = state.previous_frame();
    report(&frame.counters, frame.end_time - frame.begin_time)
}

fn report(counter : &ProfilerCounter, time : f64) -> ProfilerReport {
    ProfilerReport {
        name        : counter.name.clone(),
        time        : counter.time,
        percent     : counter.time / time * 100.0,
        sub_reports : counter.counters.iter().map(|x| report(x, counter.time)).collect()
    }
}

#[test]
fn test_print_region_time() {
    let _ : i32 = print_region_time!({
        (1 ..).take(1000).fold(0, |x, y| x + y)
    }, "Something time tooked: {}");
}

#[test]
fn test_track_regions() {
    {
        profile_region!("Main region");

        (1 ..).take(500000).fold(0, |x, y| ((x * y) as f32).sqrt().sin() as i32 + 1);

        {
            profile_region!("subregion 1");
            (1 ..).take(500000).fold(0, |x, y| ((x * y) as f32).sqrt().sin() as i32 + 1);
        }

        {
            profile_region!("subregion 2");
            (1 ..).take(500000).fold(0, |x, y| ((x * y) as f32).sqrt().sin() as i32 + 1);

            {
                profile_region!("subsubregion 1");
                (1 ..).take(500000).fold(0, |x, y| ((x * y) as f32).sqrt().sin() as i32 + 1);
            }

            {
                profile_region!("subsubregion 2");
                (1 ..).take(500000).fold(0, |x, y| ((x * y) as f32).sqrt().sin() as i32 + 1);
            }

        }

        {
            profile_region!("subregion 3");
            (1 ..).take(500000).fold(0, |x, y| ((x * y) as f32).sqrt().sin() as i32 + 1);
        }
    }

    profiler_next_frame();

    println!("{:?}", profiler_report());
}