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
//! Provides the [`profile`](crate::profile) macro or a dummy implementation depending on the selected feature
/// Creates a scope for profiling
///
/// This macro provides profiling inspired by the [`coarse-prof`](https://crates.io/crates/coarse-prof) crate.
/// The biggest difference to `coarse-prof` is that it supports profiling in multi-threaded programs.
///
/// Note that this macro only works when the `profiling` feature is enabled. Otherwise a dummy
/// implementation is provided with the same rules that expand to nothing. This allows the user to
/// disable this coarse grained profiling without modifying code depending on this macro. This can
/// be helpful to minimize overhead when using more elaborate profiling approaches.
///
/// Profiling works using scope guards that increment a thread local [`Profiler`](crate::profiling::Profiler)
/// (stored in the static [`PROFILER`](static@crate::profiling::PROFILER) variable) when they are dropped.
/// To evaluate the collected timings, the [`write`](crate::profiling::write) function can be used.
///
/// The [`write`](crate::profiling::write) function produces a human readable, hierarchically
/// structured overview of the gathered profiling data, like this:
/// ```text
/// frame: 100.00%, 10.40ms/call @ 96.17Hz
/// physics: 3.04%, 3.16ms/call @ 9.62Hz
/// collisions: 33.85%, 1.07ms/call @ 9.62Hz
/// render: 96.84%, 10.07ms/call @ 96.17Hz
/// ```
/// It collects the timings over all threads and accumulates total runtime and number of calls for
/// scopes at the same point in the call graph. As it is not easily possible to automatically connect
/// the graph across thread boundaries, this is possible manually using one of the macro rules
/// explained below.
///
/// The `profile!` macro locally returns a scope guard tracking the time instant when it was invoked.
/// Note that this guard is stored in a variable called `_profiling_scope_guard` which can result
/// in shadowing.
///
/// Note that even though it is safe to transfer a scope guard across threads, this does lead to
/// inconsistent timings when it is dropped. So this is most certainly not what you want to do.
/// Transferring [`ScopeId`](crate::profiling::ScopeId)s across thread boundaries however does make
/// sense when a to manually assign a parent scope across threads.
///
/// There are four ways to use this macro.
/// 1. A simple scope with a name. The nesting of this scope in the profiling hierarchy is inferred from the
/// scope that is surrounding the new scope on the current thread.
/// ```ignore
/// {
/// profile!("new scope")
/// }
/// ```
/// 2. A simple scope with a name and an id. An id of a new scope can be stored explicitly in a variable
/// named by the user (`scope_id` here). This can be used by other scopes to manually assign it a
/// parent scope in the profiling hierarchy.
/// ```ignore
/// {
/// profile!(scope_id, "new scope")
/// }
/// ```
/// 3. A scope with a manually specified parent scope. As the profiling macros cannot automatically infer
/// the hierarchy across threads, it is possible to manually assign a scope to a parent scope.
/// ```ignore
/// {
/// profile!(scope_id, "outer scope")
/// {
/// vec.par_iter().for_each(|item| {
/// profile!("inner scope", parent = scope_id);
/// });
/// }
/// }
/// ```
/// 4. The second and third option can be combined:
/// ```ignore
/// profile!(inner_id, "inner scope", parent = outer_id);
/// ```
/// No-op macro if profiling is disabled