1# profiling 2 3Provides a very thin abstraction over instrumented profiling crates like `puffin`, `optick`, `tracy`, and `superluminal-perf`. 4 5Mark up your code like this: 6 7```rust 8#[profiling::function] 9fn some_function() { 10 burn_time(5); 11 12 for i in 0..5 { 13 profiling::scope!("Looped Operation"); 14 } 15} 16``` 17 18See below for resulting visualization and more details on the exposed API. 19 20**Friendly Warning:** Some profiler backends implicitly listen on network ports immediately when the host app is 21launched. If this is a concern, please review the enabled profiler(s) documentation for details! 22 23## Puffin 24 25* https://github.com/EmbarkStudios/puffin 26* Cross-platform 27* Unlike the other backends, `puffin` relies on your app providing an imgui window to draw the UI in-process. The 28below screenshots have a profiled application open with the puffin imgui window visible. 29 30## Optick 31 32* https://github.com/bombomby/optick 33* The upstream crate only provides binaries for windows. However it could probably be made to work by building 34optick capture code and linking against it manually. The UI is windows only. 35 36[![Optick](screenshots/optick-small.png)](screenshots/optick.jpeg) 37 38## Superluminal 39 40* https://superluminal.eu 41* Windows only 42 43[![Superluminal](screenshots/superluminal-small.png)](screenshots/superluminal.jpeg) 44 45## Tracing 46 47* https://crates.io/crates/tracing 48* Cross-platform 49* The tracing backend injects tracing `span!()` macros that match the lifetime of the profiling macros. 50Tracing uses callbacks rather than inlining specific pre-determined code, 51so it is more flexible than profiling 52(at the cost of more lines of code and potentially higher overhead). 53This allows existing and new tracing-compatible handlers to work with profiling. 54 55![Tracing](screenshots/tracing.png) 56 57## Tracy 58 59* https://github.com/wolfpld/tracy 60* Cross-platform (windows, macOS, linux) 61 62[![Tracy](screenshots/tracy-small.png)](screenshots/tracy.jpeg) 63 64## Usage 65 66Currently, there's just four macros: 67 * `profiling::scope!(name: &str, [tag: &str])` 68 * name: scopes will appear in the profiler under this name 69 * tag: optional extra data 70 * `#[profiling::function]` 71 * procmacro placed on a function to quickly wrap it in a scope using the function name 72 * `profiling::register_thread!([name: &str])` 73 * name: optional, defaults to `std::thread::current().name`, or `.id` if it's unnamed 74 * `profiling::finish_frame!()` 75 * Many profilers have the concept of a "frame" as a unit of work. Use this to indicate where one frame ends and the 76 next one begins. 77 78Support for individual profilers can be turned on/off with feature flags. By default, they're all off, resulting in 79no dependencies or runtime code. 80 81## Who is this for? 82 * Authors of binaries that want to have multiple options for profiling their code, but don't want to duplicate their 83 instrumentation once per each profiler's individual API. 84 * Authors of libraries that would like to instrument their crate for their end-users. 85 86This crate is intended to be **TINY**. It won't support every possible usage, just the basics. I'm open to adding 87more things but I plan to be very selective to maintain a slim size. 88 89When enabled, using a macro produces identical code as if you used the wrapped profiling API directly. So it is 90completely fine to directly use a profiler's API when this abstraction doesn't support something you want to do. 91 92## Alternatives 93 94**tracing**: `tracing` is more flexible than `profiling` but is significantly larger and has 95some potential runtime cost. `profiling` is only useful for instrumented profiling. Instrumentation is inserted directly 96into your code inline via macros as if you were using the profiler's crate directly. This results in smaller code with 97no additional overhead. 98 99Using profiling crates (i.e. puffin/optick/etc.) directly: 100 * For authors of binaries, you may still need to use APIs on those crates to get started. But when instrumenting your 101 code, `profiling::scope!("Scope Name")` inside a function or `#[profiling::function]` on a function will instrument 102 it for all the supported profiler-specific crates. You can still use those crates directly if you want to take 103 advantage of custom APIs they provide to surface additional data. 104 * For authors of upstream libraries, this crate lets you implement simple instrumentation once. Hopefully this will 105 allow the community to benefit from instrumented profiling, even if a significant amount of a codebase is made 106 of upstream crates. 107 108## Using from a Binary 109 110It's up to you to initialize the profiling crate of your choice (although some do not need explicit initialization 111and will immediately work). The examples demonstrate this for all the supported crates, but it's worth looking 112at the docs for the profiler you're interested in using! `profiling` re-exports the profiler crates if they are 113enabled, simplifying the modifications you would need to make to your Cargo.toml. 114 115Once initialized, you can mix/match the macros provided by your profiler of choice and the generic ones in this 116crate. For example: 117 118```rust 119// This may map to something like: 120// - puffin::profile_scope!("Scope Name") 121// - optick::event!("Scope Name") 122// - tracing::span!(tracing::Level::INFO, "Scope Name") 123// - superluminal_perf::begin_event("Scope Name") 124profiling::scope!("Scope Name"); 125 126// This may map to something like: 127// - puffin::profile_scope_data!("Scope Name", "extra data") 128// - optick::event!("Scope Name"); optick::tag!("tag", "extra data"); 129// - tracing::span!(tracing::Level::INFO, "Scope Name", tag = "extra data") 130// - superluminal_perf::begin_event_with_data("Scope Name", "extra data", 0) 131profiling::scope!("Scope Name", "extra data"); 132``` 133 134There is also a proc macro to decorate functions: 135 136```rust 137#[profiling::function] 138fn my_function() { 139 140} 141``` 142 143Take a look at the code for the helpful macros `register_thread!()` and `finish_frame!()`. 144 145I recommend adding features for each backend you want to use to your binary crate. This allows you to optionally compile 146in code to setup and configure a backend. 147 148```toml 149[dependencies] 150profiling = "1.0" 151 152[features] 153profile-with-puffin = ["profiling/profile-with-puffin"] 154profile-with-optick = ["profiling/profile-with-optick"] 155profile-with-superluminal = ["profiling/profile-with-superluminal"] 156profile-with-tracing = ["profiling/profile-with-tracing"] 157profile-with-tracy = ["profiling/profile-with-tracy"] 158``` 159 160 * You can use the default feature to quickly/temporarily turn something on: `default = ["profile-with-optick"]` 161 * `cargo run --features=profile-with-optick` works too! 162 163## Using from a Library 164 165Add the profiling crate to Cargo.toml: 166 167```toml 168[dependencies] 169profiling = "1.0" 170``` 171 172Now you can instrument your library using the API exposed via the `profiling` crate. 173 174If the end-user of your library doesn't use profiling, the macros in this crate will emit no code at all. 175 176## Feature Flags 177 178 * profile-with-puffin: Enable the `puffin` crate 179 * profile-with-optick: Enable the `optick` crate 180 * profile-with-superluminal: Enable the `superluminal-perf` crate 181 * profile-with-tracing: Enable the `tracing` crate. (This is just an abstraction layer - you'd want to hook it to do something!) 182 * profile-with-tracy: Enable the `tracy-client` crate. 183 184**Only one backend can be enabled at a time!** 185 186## Examples 187 188 * simple: Shows a bare minimum requirements to do some simple instrumented profiling. Once it's running, you 189 can connect to the process using optick/tracy/superluminal. Some of these are windows only! 190 191``` 192run --example simple --features="profile-with-optick" 193run --example simple --features="profile-with-tracy" 194run --example simple --features="profile-with-puffin" 195run --example simple --features="profile-with-superluminal" 196``` 197 198 * puffin: Launches a basic app with imgui integration showing the puffin UI. This one should run everywhere 199 that supports imgui. 200 201``` 202cargo run --example puffin --features="profile-with-puffin" 203``` 204 205## License 206 207Licensed under either of 208 209* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) 210* MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) 211 212at your option. 213 214The examples directory contains [`NotoSans-Medium.ttf`](https://www.google.com/get/noto/), available under SIL Open Font 215License (OFL). 216 217### Contribution 218 219Unless you explicitly state otherwise, any contribution intentionally 220submitted for inclusion in the work by you, as defined in the Apache-2.0 221license, shall be dual licensed as above, without any additional terms or 222conditions. 223 224See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT). 225