Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add extended version of puffin::profile_scope!() #213

Merged
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 56 additions & 12 deletions puffin/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,24 +231,47 @@ macro_rules! profile_function {
};
}

#[allow(clippy::doc_markdown)] // clippy wants to put "MacBook" in ticks 🙄

/// Profile the current scope with the given name (unique in the parent scope).
///
/// This macro is identical to [profile_scope], except that it expands to the expression
/// containing the profiling scope, as opposed to [profile_scope] which expands to a
/// variable (which cannot be accessed due to macro hygiene).
///
/// Names should be descriptive, ASCII and without spaces.
///
/// Example: `profile_scope!("load_mesh");`.
/// This allows for profiling scopes to persist for a custom duration.
///
/// # Example
///
/// ```rust
/// # use std::iter::FromIterator as _;
/// #
/// # pub mod rayon { pub mod prelude {
/// # pub fn for_each_init<T, I>(vec: &std::vec::Vec<T>, init: fn() -> I, body: fn ((I, T)) -> ()) {
/// # }
/// # } }
/// #
/// let some_large_vec = Vec::from_iter(0..1000);
///
/// An optional second argument can be a string (e.g. a mesh name) to help diagnose what was slow.
/// Example: `profile_scope!("load_mesh", mesh_name);`
///
/// Overhead: around 54 ns on Macbook Pro with Apple M1 Max.
/// // Use rayon's parallel for loop over our large iterator
/// rayon::prelude::for_each_init(
/// &some_large_vec,
/// // This gets called to init each work segment, and is passed into the calls
/// // Rayon keeps the profiling scope stored for the entire duration of the work segment
/// // So we can track the entire segment as one, instead of each loop iteration
/// || puffin::profile_scope_custom!("rayon_work_segment"),
/// |((_profiler_scope), i)| {
/// // All calls here gets profiled on the same scope
/// println!("{i}")
/// },
/// );
/// ```
#[macro_export]
macro_rules! profile_scope {
macro_rules! profile_scope_custom {
($name:expr) => {
$crate::profile_scope!($name, "");
$crate::profile_scope_custom!($name, "")
};
($name:expr, $data:expr) => {
v0x0g marked this conversation as resolved.
Show resolved Hide resolved
let _profiler_scope = if $crate::are_scopes_on() {
if $crate::are_scopes_on() {
static SCOPE_ID: std::sync::OnceLock<$crate::ScopeId> = std::sync::OnceLock::new();
let scope_id = SCOPE_ID.get_or_init(|| {
$crate::ThreadProfiler::call(|tp| {
Expand All @@ -264,7 +287,28 @@ macro_rules! profile_scope {
Some($crate::ProfilerScope::new(*scope_id, $data))
} else {
None
};
}
};
}

#[allow(clippy::doc_markdown)] // clippy wants to put "MacBook" in ticks 🙄
/// Profile the current scope with the given name (unique in the parent scope).
///
/// Names should be descriptive, ASCII and without spaces.
///
/// Example: `profile_scope!("load_mesh");`.
///
/// An optional second argument can be a string (e.g. a mesh name) to help diagnose what was slow.
/// Example: `profile_scope!("load_mesh", mesh_name);`
///
/// Overhead: around 54 ns on Macbook Pro with Apple M1 Max.
#[macro_export]
macro_rules! profile_scope {
($name:expr) => {
$crate::profile_scope!($name, "");
};
($name:expr, $data:expr) => {
let _profiler_scope = $crate::profile_scope_custom!($name, $data);
};
}

Expand Down