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
//! # 🚄 Profiler API
//!
//! This provides bindings between the Puffin Profiler library and Ark.
//!
//! ## Usage
//!
//! In `Cargo.toml`:
//! * Add `"profiler"` to the `ark` `features` list.
//!
//! In your `lib.rs` you need a call `require_profiler_api();`.
//! To enable profiling you need to call `ark::setup_profiler!();` from your
//! module entry point.
//!
//! Now you can add profile scopes with `ark::profiler::function!();`
//! in functions you want to profile.
//!
//! You should now be able to see your profile scopes in the ark-client profiler window.
//!
//! It is also recommended that you call `ark::profiler::set_scopes_on(ark::profiler::is_active());`
//! on each frame update, to allow `ark-client` to switch the module profiler on/off.

use crate::ffi::profiler_v0 as ffi;

#[doc(hidden)]
pub use ffi::API as FFI_API;

/// This can be used as the optional argument to the profile macros to mark them
/// as something to show when doing simple profile measurements from ark-client.
pub const INCLUDE_SIMPLE: &str = "_simple";

/// Current time in nanoseconds, from some unspecified event.
///
/// Used for high precision profiling and is only supported for profiling. May return 0 if profiling is not enabled.
/// Can't be used for absolute time determination, only relative difference between calls.
#[inline]
pub fn now_ns() -> i64 {
    ffi::now_ns()
}

/// Report Puffin profiler event stream
///
/// Used by the puffin profiler running in user space to report
/// profiler events to the host profiler instance.
#[inline]
pub fn report_thread_stream_info(stream_info: &puffin::StreamInfoRef<'_>) {
    let puffin::StreamInfoRef {
        stream,
        num_scopes,
        depth,
        range_ns: (range_ns_min, range_ns_max),
    } = stream_info;
    let stream_meta = ffi::StreamMeta {
        num_scopes: *num_scopes as _,
        depth: *depth as _,
        range_ns_min: *range_ns_min,
        range_ns_max: *range_ns_max,
    };
    ffi::report_thread_stream_info(&stream_meta, stream);
}

/// Is the module-side profiler on?
///
/// Call `puffin::set_scopes_on(ark::profiler::is_active());`
/// at the top of each frame to heed this.
#[inline]
pub fn is_active() -> bool {
    ffi::is_active()
}

// re-export key profiling macros from puffin
//
// this makes it easier for the user as they do not have to depend on the
// puffin crate themselves and match the right version.
pub use puffin::profile_function as function;
pub use puffin::profile_scope as scope;
pub use puffin::set_scopes_on;

// The following two macros are used to be able to have some basic scopes that are always enabled,
// even if all scopes are not enabled with `set_scopes_on()`.
// TODO: We should probably move this feature into puffin, and possibly include several levels
// to set granularity for the scopes you want enabled.

/// Like [`function!`] macro, but will always do the scope even if module profiling is disabled.
#[macro_export]
macro_rules! __function_always {
    () => {
        $crate::__function_always!("");
    };
    ($data:expr) => {
        let _profiler_scope = $crate::__puffin::ProfilerScope::new(
            $crate::__puffin::current_function_name!(),
            $crate::__puffin::current_file_name!(),
            $data,
        );
    };
}
pub use __function_always as function_always;

/// Like [`scope!`] macro, but will always do the scope even if module profiling is disabled.
#[macro_export]
macro_rules! __scope_always {
    ($id:expr) => {
        $crate::__scope_always!($id, "");
    };
    ($id:expr, $data:expr) => {
        let _profiler_scope = $crate::__puffin::ProfilerScope::new(
            $id,
            $crate::__puffin::current_file_name!(),
            $data,
        );
    };
}
pub use __scope_always as scope_always;

/// Call at least once from your Module setup code to enable profiling
/// using the `puffin` profiler.
#[macro_export]
macro_rules! setup_profiler {
    () => {
        $crate::__puffin::ThreadProfiler::initialize(
            $crate::profiler::now_ns,
            |_thread_info, stream_info| $crate::profiler::report_thread_stream_info(stream_info),
        );
        $crate::__puffin::set_scopes_on($crate::profiler::is_active());
    };
}