tinyprof/
lib.rs

1extern crate time;
2#[macro_use] extern crate lazy_static;
3
4mod profiler_frame;
5mod profiler_state;
6
7use std::sync::Mutex;
8use time::precise_time_s;
9use std::ops::Drop;
10
11pub use profiler_frame::*;
12pub use profiler_state::*;
13
14lazy_static! {
15    pub static ref PROFILER_STATE: Mutex<ProfilerState> = Mutex::new(ProfilerState::new());
16}
17
18#[derive(Debug)]
19pub struct ProfilerReport {
20    pub name        : String,
21    pub time        : f64,
22    pub percent     : f64,
23    pub sub_reports : Vec<ProfilerReport>
24}
25
26pub fn profiler_report() -> ProfilerReport {
27    state_report(&mut *PROFILER_STATE.lock().unwrap())
28}
29pub fn profiler_next_frame() {
30    PROFILER_STATE.lock().unwrap().next_frame();
31}
32
33pub struct ProfilerRegion {
34    pub enter_time : f64,
35    pub name       : String
36}
37impl ProfilerRegion {
38    pub fn new(name : &str) -> ProfilerRegion {
39        PROFILER_STATE.lock().unwrap().begin_track_time(name.to_string());
40        ProfilerRegion {
41            enter_time : precise_time_s(),
42            name       : name.to_string()
43        }
44    }
45}
46impl Drop for ProfilerRegion {
47    fn drop(&mut self) {
48        PROFILER_STATE.lock().unwrap().end_track_time(precise_time_s() - self.enter_time);
49    }
50}
51
52
53#[macro_export]
54macro_rules! profile_region {
55    ($name:expr) => {
56        let _profile = $crate::ProfilerRegion::new($name);
57    }
58}
59
60#[macro_export]
61macro_rules! print_region_time {
62    ($x:expr, $pattern:expr) => {{
63        use time::precise_time_s;
64
65        let start = precise_time_s();
66        let res = $x;
67        let end = precise_time_s();
68        println!($pattern, end - start);
69        res
70    }};
71}
72
73pub fn state_report(state : &mut ProfilerState) -> ProfilerReport {
74    let frame = state.previous_frame();
75    report(&frame.counters, frame.end_time - frame.begin_time)
76}
77
78fn report(counter : &ProfilerCounter, time : f64) -> ProfilerReport {
79    ProfilerReport {
80        name        : counter.name.clone(),
81        time        : counter.time,
82        percent     : counter.time / time * 100.0,
83        sub_reports : counter.counters.iter().map(|x| report(x, counter.time)).collect()
84    }
85}
86
87#[test]
88fn test_print_region_time() {
89    let _ : i32 = print_region_time!({
90        (1 ..).take(1000).fold(0, |x, y| x + y)
91    }, "Something time tooked: {}");
92}
93
94#[test]
95fn test_track_regions() {
96    {
97        profile_region!("Main region");
98
99        (1 ..).take(500000).fold(0, |x, y| ((x * y) as f32).sqrt().sin() as i32 + 1);
100
101        {
102            profile_region!("subregion 1");
103            (1 ..).take(500000).fold(0, |x, y| ((x * y) as f32).sqrt().sin() as i32 + 1);
104        }
105
106        {
107            profile_region!("subregion 2");
108            (1 ..).take(500000).fold(0, |x, y| ((x * y) as f32).sqrt().sin() as i32 + 1);
109
110            {
111                profile_region!("subsubregion 1");
112                (1 ..).take(500000).fold(0, |x, y| ((x * y) as f32).sqrt().sin() as i32 + 1);
113            }
114
115            {
116                profile_region!("subsubregion 2");
117                (1 ..).take(500000).fold(0, |x, y| ((x * y) as f32).sqrt().sin() as i32 + 1);
118            }
119
120        }
121
122        {
123            profile_region!("subregion 3");
124            (1 ..).take(500000).fold(0, |x, y| ((x * y) as f32).sqrt().sin() as i32 + 1);
125        }
126    }
127
128    profiler_next_frame();
129
130    println!("{:?}", profiler_report());
131}