Crates.io | profiling-procmacros |
lib.rs | profiling-procmacros |
version | 1.0.16 |
source | src |
created_at | 2020-11-26 08:24:03.190507 |
updated_at | 2024-10-14 03:42:39.83733 |
description | This crate provides a very thin abstraction over other profiler crates. |
homepage | https://github.com/aclysma/profiling |
repository | https://github.com/aclysma/profiling |
max_upload_size | |
id | 316630 |
size | 16,486 |
Provides a very thin abstraction over instrumented profiling crates like puffin
, optick
, tracy
, and superluminal-perf
.
Mark up your code like this:
#[profiling::function]
fn some_function() {
burn_time(5);
for i in 0..5 {
profiling::scope!("Looped Operation");
}
}
See below for resulting visualization and more details on the exposed API.
Friendly Warning: Some profiler backends implicitly listen on network ports immediately when the host app is launched. If this is a concern, please review the enabled profiler(s) documentation for details!
profiling::finish_frame!()
at least once per framepuffin_http
and puffin_viewer
, or if you're writing an egui
app, use puffin_egui
.span!()
macros that match the lifetime of the profiling macros.
Tracing uses callbacks rather than inlining specific pre-determined code,
so it is more flexible than profiling
(at the cost of more lines of code and potentially higher overhead).
This allows existing and new tracing-compatible handlers to work with profiling.Currently, there's just six macros:
profiling::scope!(name: &str, [tag: &str])
#[profiling::function]
#[profiling::all_functions]
#[profiling::function]
on each function under that struct impl block#[profiling::skip]
#[profiling::all_functions]
, placed this procmacro on a function to avoid the action that #[profiling::all_functions]
applyprofiling::register_thread!([name: &str])
std::thread::current().name
, or .id
if it's unnamedprofiling::finish_frame!()
profiling::function_scope!([tag: &str])
Support for individual profilers can be turned on/off with feature flags. By default, they're all off, resulting in no dependencies or runtime code.
This crate is intended to be TINY. It won't support every possible usage, just the basics. I'm open to adding more things but I plan to be very selective to maintain a slim size.
When enabled, using a macro produces identical code as if you used the wrapped profiling API directly. So it is completely fine to directly use a profiler's API when this abstraction doesn't support something you want to do.
tracing: tracing
is more flexible than profiling
but is significantly larger and has
some potential runtime cost. profiling
is only useful for instrumented profiling. Instrumentation is inserted directly
into your code inline via macros as if you were using the profiler's crate directly. This results in smaller code with
no additional overhead.
Using profiling crates (i.e. puffin/optick/etc.) directly:
profiling::scope!("Scope Name")
inside a function or #[profiling::function]
on a function will instrument
it for all the supported profiler-specific crates. You can still use those crates directly if you want to take
advantage of custom APIs they provide to surface additional data.It's up to you to initialize the profiling crate of your choice (although some do not need explicit initialization
and will immediately work). The examples demonstrate this for all the supported crates, but it's worth looking
at the docs for the profiler you're interested in using! profiling
re-exports the profiler crates if they are
enabled, simplifying the modifications you would need to make to your Cargo.toml.
Once initialized, you can mix/match the macros provided by your profiler of choice and the generic ones in this crate. For example:
// This may map to something like:
// - puffin::profile_scope!("Scope Name")
// - optick::event!("Scope Name")
// - tracing::span!(tracing::Level::INFO, "Scope Name")
// - superluminal_perf::begin_event("Scope Name")
profiling::scope!("Scope Name");
// This may map to something like:
// - puffin::profile_scope_data!("Scope Name", "extra data")
// - optick::event!("Scope Name"); optick::tag!("tag", "extra data");
// - tracing::span!(tracing::Level::INFO, "Scope Name", tag = "extra data")
// - superluminal_perf::begin_event_with_data("Scope Name", "extra data", 0)
profiling::scope!("Scope Name", "extra data");
There is also a proc macro to decorate functions:
#[profiling::function]
fn my_function() {
}
Take a look at the code for the helpful macros register_thread!()
and finish_frame!()
.
I recommend adding features for each backend you want to use to your binary crate. This allows you to optionally compile in code to setup and configure a backend.
[dependencies]
profiling = "1.0"
[features]
profile-with-puffin = ["profiling/profile-with-puffin"]
profile-with-optick = ["profiling/profile-with-optick"]
profile-with-superluminal = ["profiling/profile-with-superluminal"]
profile-with-tracing = ["profiling/profile-with-tracing"]
profile-with-tracy = ["profiling/profile-with-tracy"]
default = ["profile-with-optick"]
cargo run --features=profile-with-optick
works too!Add the profiling crate to Cargo.toml:
[dependencies]
profiling = "1.0"
Now you can instrument your library using the API exposed via the profiling
crate.
If the end-user of your library doesn't use profiling, the macros in this crate will emit no code at all.
puffin
crateoptick
cratesuperluminal-perf
cratetracing
crate. (This is just an abstraction layer - you'd want to hook it to do something!)tracy-client
crate.Only one backend can be enabled at a time!
run --example simple --features="profile-with-optick"
run --example simple --features="profile-with-tracy"
run --example simple --features="profile-with-puffin"
run --example simple --features="profile-with-superluminal"
cargo run --example puffin --features="profile-with-puffin"
This project will strive to keep a conservative MSRV, but some backends will support a lower MSRV than others. The MSRV set in this project only represents the MSRV for compiling the profiling crate with no backends enabled.
As a point of reference, currently the most popular crate relying on profiling is wgpu, and their
MSRV is constrained to Firefox nightly build MSRV. So the MSRV of this crate (ignoring backends)
should not move faster than wgpu and firefox nightly. (See MINIMUM_RUST_VERSION
in
python/mozboot/mozboot/util.py
)
Licensed under either of
at your option.
The examples directory contains NotoSans-Medium.ttf
, available under SIL Open Font
License (OFL).
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
See LICENSE-APACHE and LICENSE-MIT.