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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
//! This crate provides the tools to benchmark code for
//! further analyzation using Chrome tracing.
//!
//! # Examples
//!
//! - Examples of using gbench basic functionality
//! ```rust
//! use gbench::{instantiate, scope};
//!
//! fn main() {
//!     // Istantiation of the global variables
//!     // It is needed at the top of every program that uses gbench
//!     // The folder that is specified is the folder where the data
//!     // will be saved
//!     instantiate!("target/bench");
//!     {
//!         // This macro creates a variable that starts benchmarking
//!         // on creation and saves the result on drop.
//!         // The variable name is the first argument, the scope name
//!         // is the second.
//!         scope!(sc | "Scope");
//!
//!         for _ in 0..1_000_000 {
//!             let _a = 1 + 1;
//!         }
//!     }
//! }
//! ```
//!
//! - Example of a [log!] macro use
//! ```rust
//! use gbench::{instantiate, log, scope};
//!
//! fn main() {
//!     instantiate!(ginst | "target/bench");
//!     {
//!         scope!(sc | "Scope");
//!
//!         for _ in 0..1_000 {
//!             let a = 1 + 1;
//!
//!             // You can log to the file with a timestamp
//!             // using log! macro
//!             log!("A = {}", a);
//!         }
//!     }
//! }
//! ```
//!
//! - Full example
//! ```rust
//! use std::thread;
//!
//! use gbench::{instantiate, scope};
//!
//! fn calculate(num: f32, n: u32) -> f32 {
//!     (0..n)
//!         .fold((num, 0.0), |(x, v), _| (x + v * 0.01, v - x * 0.001))
//!         .0
//! }
//!
//! fn main() {
//!     instantiate!("target/bench");
//!
//!     scope!(program_scope | "Program scope");
//!
//!     // Doing the work that needs benchmarking
//!     for _ in 0..5 {
//!         scope!(main | "Main scope");
//!
//!         // Spawning a thread to do work
//!         let thread = thread::spawn(move || {
//!             // This benchmarks the scope that it is in
//!             scope!(child | "Child");
//!
//!             calculate(1.0, 1_500_000)
//!         });
//!
//!         // You can organize your subtasks in scopes to
//!         // benchmark them
//!         scope!(imp | "An important task");
//!
//!         {
//!             scope!(i1 | "Important subtask");
//!             calculate(1.0, 300_000);
//!         }
//!
//!         {
//!             scope!(i2 | "Less important subtask");
//!             calculate(1.0, 500_000);
//!         }
//!
//!         // If the block of code that you need to benchmark
//!         // has ended you can drop the guard if the scope
//!         // has not ended
//!         drop(imp);
//!
//!         // Marking the start of another task
//!         scope!(join | "Joining thread");
//!
//!         thread.join().unwrap();
//!
//!         // This line of code is unnecessary but I like
//!         // to keep it
//!         drop(join);
//!     }
//! }
//! ```
//!
//! [log!]: macro.log.html

mod bench;
mod global;
mod id;

pub use bench::Instantiator;
pub use bench::TimeScope;

#[doc(hidden)]
pub use bench::_log;

/// A macro for benchmarking a scope of code
///
/// ```
/// scope!(main)
/// // expands into this
/// let main = TimeScope::new(format!("main"));
/// ```
///
/// ```
/// scope!(main | "A {}", 0)
/// // expands into this
/// let main = TimeScope::new(format!("A {}", 0));
/// ```
#[cfg(debug_assertions)]
#[macro_export]
macro_rules! scope {
    ($name:ident) => {
        scope!($name | stringify!(name));
    };

    ($name:ident | $($arg:tt)*) => {
        let $name = {
            use gbench::TimeScope;
            TimeScope::new(format!($($arg)*))
        };
    };
}

#[cfg(not(debug_assertions))]
#[macro_export]
macro_rules! scope {
    ($name:ident) => {};

    ($name:ident|$($arg:tt)*) => {};
}

/// A macro for instantiating the global environment for benchmark logging.
///
/// This macro should be used at the top of any program using this crate.
///
/// ```
/// instantiate!("target/bench");
/// // expands into this
/// let __gbench_instantiator__ = Instantiator::new("target/bench");
/// ```
///
/// ```
/// instantiate!(ginst | "target/bench");
/// // expands into this
/// let ginst = Instnatiator::new("target/bench");
/// ```
/// The second option is used when you need to use [end] on the instance.
///
/// [end]: struct.Instantiator.html#method.end
#[cfg(debug_assertions)]
#[macro_export]
macro_rules! instantiate {
    ($name: ident | $folder:expr) => {
        let mut $name = {
            use gbench::Instantiator;
            Instantiator::new($folder)
        };
    };

    ($folder:expr) => {
        instantiate!(__global_instantiator__ | $folder);
    };
}

#[cfg(not(debug_assertions))]
#[macro_export]
macro_rules! instantiate {
    ($folder: expr) => {};
}

/// A macro for logging an event.
///
/// ```
/// let a = 0;
/// log!("A: {}", a);
/// ```
/// will write this to the benchmarking file
/// ```
/// {
///   "cat": "log",
///   "name": "A: 0",
///   "ph": "I",
///   "pid": 0,
///   "tid": 0,
///   "ts": /* current timestamp */
/// }
/// ```
#[cfg(debug_assertions)]
#[macro_export]
macro_rules! log {
    ($($arg:tt)*) => {
        {
            use gbench::_log as log;
            let log_string = format!($($arg)*);
            log(log_string);
        }
    };
}

#[cfg(not(debug_assertions))]
#[macro_export]
macro_rules! log {
    ($($arg:tt)*) => {};
}