time_graph/lib.rs
1//! [`time-graph`] provides always-on profiling for your code, allowing to
2//! record the execution time of functions, spans inside these functions and the
3//! full call graph of spans and functions at run-time.
4//!
5//! # Core concepts
6//!
7//! There are two main concepts in this crate: [`CallSite`] identify a single
8//! call site in the source, usually a full function. One can then create a
9//! [`Span`] from any callsite, representing a single execution of the code.
10//! When executed, the [`Span`] will its elapsed time, and store it in the
11//! global call graph.
12//!
13//! # Controlling data collection
14//!
15//! By default, no data is collected until you call [`enable_data_collection`]
16//! to start collecting timing data. Once you are done running your code, you
17//! can extract collected data with [`get_full_graph`], and possibly clear all
18//! collected data using [`clear_collected_data`].
19//!
20//! [`time-graph`]: https://crates.io/crates/time-graph
21//!
22//! # Overhead and limitations
23//!
24//! When data collection is disabled, this crate adds an overheard around 10 ns
25//! when calling a function or entering a span. With data collection enabled,
26//! this crate adds an overhead around 100 ns when calling a function or
27//! entering a span.
28//!
29//! This makes this crate only useful for gathering profiling data on
30//! function/spans taking at least 1 µs to execute.
31//!
32//! # Crate features
33//!
34//! This crate has two cargo features:
35//!
36//! - **json**: enables json output format for the full call graph
37//! - **table**: enables pretty-printing the full call graph to a table using
38//! [term-table](https://crates.io/crates/term-table)
39
40#![allow(clippy::redundant_field_names, clippy::needless_return)]
41
42pub use time_graph_macros::instrument;
43
44#[doc(hidden)]
45pub use once_cell::sync::Lazy;
46
47/// Create a new [`CallSite`] with the given name at the current source
48/// location.
49///
50/// # Examples
51/// ```
52/// use time_graph::{CallSite, callsite};
53///
54/// let callsite: &'static CallSite = callsite!("here");
55/// assert_eq!(callsite.name(), "here");
56/// ```
57#[macro_export]
58macro_rules! callsite {
59 ($name: expr) => {
60 {
61 static CALL_SITE: $crate::Lazy<$crate::CallSite> = $crate::Lazy::new(|| {
62 $crate::CallSite::new(
63 $name,
64 module_path!(),
65 file!(),
66 line!(),
67 )
68 });
69 static REGISTRATION: $crate::Lazy<()> = $crate::Lazy::new(|| {
70 $crate::register_callsite(&*CALL_SITE)
71 });
72 $crate::Lazy::force(®ISTRATION);
73
74 &*CALL_SITE
75 }
76 };
77}
78
79/// Run a block of code inside a new span
80///
81/// This macro creates a new [`CallSite`] with the given name at the current
82/// source location, and record the provided code execution by running it inside
83/// a [`Span`].
84///
85/// # Examples
86/// ```
87/// use time_graph::spanned;
88///
89/// let result = spanned!("named", {
90/// let first = 30;
91/// let second = 12;
92/// first + second
93/// });
94///
95/// assert_eq!(result, 42);
96/// ```
97#[macro_export]
98macro_rules! spanned {
99 ($name: expr, $block: expr) => {
100 {
101 let __tfg_callsite = $crate::callsite!($name);
102 let __tfg_span = $crate::Span::new(__tfg_callsite);
103 let __tfg_guard = __tfg_span.enter();
104
105 $block
106 }
107 }
108}
109
110mod callsite;
111pub use self::callsite::CallSite;
112pub(crate) use self::callsite::CallSiteId;
113pub use self::callsite::{register_callsite, traverse_registered_callsite};
114
115mod graph;
116pub use self::graph::{Span, SpanGuard};
117pub use self::graph::{get_full_graph, clear_collected_data, enable_data_collection};
118pub use self::graph::{FullCallGraph, TimedSpan};
119
120#[cfg(feature = "table")]
121mod table;