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 thread_local! {
62 static __TG_DEPTH: ::std::cell::Cell<usize> = ::std::cell::Cell::new(0);
63 }
64 static CALL_SITE: $crate::Lazy<$crate::CallSite> = $crate::Lazy::new(|| {
65 $crate::CallSite::new(
66 &__TG_DEPTH,
67 $name,
68 module_path!(),
69 file!(),
70 line!(),
71 )
72 });
73 static REGISTRATION: $crate::Lazy<()> = $crate::Lazy::new(|| {
74 $crate::register_callsite(&*CALL_SITE)
75 });
76 $crate::Lazy::force(®ISTRATION);
77
78 &*CALL_SITE
79 }
80 };
81}
82
83/// Run a block of code inside a new span
84///
85/// This macro creates a new [`CallSite`] with the given name at the current
86/// source location, and record the provided code execution by running it inside
87/// a [`Span`].
88///
89/// # Examples
90/// ```
91/// use time_graph::spanned;
92///
93/// let result = spanned!("named", {
94/// let first = 30;
95/// let second = 12;
96/// first + second
97/// });
98///
99/// assert_eq!(result, 42);
100/// ```
101#[macro_export]
102macro_rules! spanned {
103 ($name: expr, $block: expr) => {
104 {
105 let __tg_callsite = $crate::callsite!($name);
106 let mut __tg_span = $crate::Span::new(__tg_callsite);
107 let __tg_guard = __tg_span.enter();
108
109 $block
110 }
111 }
112}
113
114mod callsite;
115pub use self::callsite::CallSite;
116pub(crate) use self::callsite::CallSiteId;
117pub use self::callsite::{register_callsite, traverse_registered_callsite};
118
119mod graph;
120pub use self::graph::{Span, SpanGuard};
121pub use self::graph::{get_full_graph, clear_collected_data, enable_data_collection};
122pub use self::graph::{FullCallGraph, TimedSpan};
123
124#[cfg(feature = "table")]
125mod table;