1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
//! A library for simple profiling your code with HTML reports as result.
//!
//! # Usage
//! At first the rprofiler must be initialized by the call `rprofiler::PROFILER.initialize()` method.
//! This method is returned an object of ProfilerData struct, where will be gathering all runtime information.
//! Then you can use special `profile_block` macro for profiling blocks of your code. It has some syntax variations:
//! ```rust
//! profile_block!();
//! profile_block!(name "name of code block");
//! // Conditional profiling
//! profile_block!(if_feature "feature name of your crate");
//! profile_block!(if_feature "feature name of your crate", name "name of code block");
//! ```
//! This macro generates special internal events, which will be pushed to internal events queue.
//! You should call the `rprofiler::PROFILER.process_events(...)` method periodically to process events and clear the queue.
//! As example, this method can be called at end of each game frame.
//!
//! At end of profiling you should call the `rprofiler::PROFILER.shutdown(...)` method.
//! It will process all gathered information and save result as HTML document into specified file.
//!
//! You can disable all profiling at compile-time by enabling a feature *"disable_profiling"* in *Cargo.toml* of your project.
//! ```toml
//! [package]
//! name = "game"
//! version = "0.1.0"
//! edition = "2018"
//!
//! [dependencies.rprofiler]
//! version = "0.2"
//! features = ["disable_profiling"]
//! ```
//!
//! # Examples
//! ```rust
//! fn factorial(value: i32) -> i32 {
//!     match value > 1 {
//!         true => value*factorial(value - 1),
//!         false => 1,
//!     }
//! }
//!
//! fn test_func() -> i32 {
//!     profile_block!();
//!     (0..10).map(|i| factorial(i)).sum()
//! }
//!
//! fn main() {
//!     let mut profiler_data = PROFILER.initialize();
//!
//!     for _ in 0..1000 {
//!         for _ in 0..1_000_000 {
//!             test_func();
//!         }
//!         PROFILER.process_events(&mut profiler_data);
//!     }
//!
//!     PROFILER.shutdown("./profiler_report.html", &mut profiler_data);
//! }
//! ```

#[macro_use] extern crate lazy_static;
extern crate flume;

pub use profiler::{ Profiler, PROFILER, ProfilerBlockGuard };

mod profiler;
mod block_stat;
mod profiler_data;

use block_stat::*;
use profiler_data::*;

#[cfg(not(feature = "disable_profiling"))]
#[macro_export]
macro_rules! profile_block {
    () => {
        let _profiler_block_guard = $crate::ProfilerBlockGuard::new({
            fn f() {}

            #[inline]
            fn type_name_of_val<T>(_: T) -> &'static str {
                std::any::type_name::<T>()
            }

            let name = type_name_of_val(f);
            &name[..name.len() - 3]
        });
    };
    (name $block_name:literal) => {
        let _profiler_block_guard = $crate::ProfilerBlockGuard::new($block_name);
    };
    (if_feature $name:literal) => {
        #[cfg(feature = $name)] profile_block!();
    };
    (if_feature $feature_name:literal, name $block_name:literal) => {
        #[cfg(feature = $feature_name)] profile_block!(name $block_name);
    };
}

#[cfg(feature = "disable_profiling")]
#[macro_export]
macro_rules! profile_block {
    () => {};
    (name $block_name:literal) => {};
    (if_feature $name:literal) => {};
    (if_feature $feature_name:literal, name $block_name:literal) => {};
}