summaryrefslogtreecommitdiffstats
path: root/profiling
diff options
context:
space:
mode:
Diffstat (limited to 'profiling')
-rw-r--r--profiling/Cargo.toml15
-rw-r--r--profiling/README.md61
-rw-r--r--profiling/src/lib.rs100
3 files changed, 176 insertions, 0 deletions
diff --git a/profiling/Cargo.toml b/profiling/Cargo.toml
new file mode 100644
index 00000000..29ee8c9c
--- /dev/null
+++ b/profiling/Cargo.toml
@@ -0,0 +1,15 @@
+[package]
+name = "iced_profiling"
+authors = ["Bingus <shankern@protonmail.com>"]
+version = "0.1.0"
+edition = "2021"
+description = "Profiling backend implementations for Iced"
+
+[dependencies]
+tracing = { version = "0.1.37", default-features = false, features = ["std"] }
+tracing-core = "0.1.30"
+tracing-subscriber = { version = "0.3.16", features = ["registry", "env-filter"] }
+
+[dependencies.tracing-chrome]
+version = "0.7.0"
+optional = true
diff --git a/profiling/README.md b/profiling/README.md
new file mode 100644
index 00000000..f150bcec
--- /dev/null
+++ b/profiling/README.md
@@ -0,0 +1,61 @@
+# `iced_profiling`
+[![Documentation](https://docs.rs/iced_profiling/badge.svg)]
+[![Crates.io](https://img.shields.io/crates/v/iced_profiling.svg)](https://crates.io/crates/iced_profiling)
+[![License](https://img.shields.io/crates/l/iced_profiling.svg)](https://github.com/iced-rs/iced/blob/master/LICENSE)
+[![Discord Server](https://img.shields.io/discord/628993209984614400?label=&labelColor=6A7EC2&logo=discord&logoColor=ffffff&color=7389D8)](https://discord.gg/3xZJ65GAhd)
+
+`iced_profiling` is a crate which implements various tracing backends for Iced.
+
+It relies on the [tracing](https://crates.io/crates/tracing) crate to collect diagnostics. We currently only support
+tracing with `tracing`'s `info_span!` macro, but will consider different logging levels in the future. PRs welcome!
+
+## Trace backends
+
+We currently support only Chrome JSON traces using the [tracing-chrome](https://crates.io/crates/tracing-chrome) crate.
+
+There are plans to add support for [Tracy](https://github.com/wolfpld/tracy) in the near future!
+
+## Generating a trace file
+
+### Using Iced's `Application`
+
+Simply enable your tracing backend of choice (e.g. `trace_chrome`) feature in Iced & run your project.
+
+```shell
+cargo run --features iced/trace_chrome
+```
+### Standalone dependency
+
+You can enable tracing by enabling your tracing backend of choice as a feature of `iced_profiling`.
+
+```toml
+iced_profiling = { version = "0.1.0", features = ["tracing-chrome"]}
+```
+
+Doing so will require you to initialize the profiler manually like so:
+
+```rust
+let _guard = iced_profiling::init();
+```
+
+This reference must be kept alive for the entire duration of your application that you wish to profile.
+
+## Chrome
+
+By default, Chrome trace files will be generated in the current working directory:
+```shell
+path/to/your/project/project_trace_{timestamp}.json
+```
+
+You also set a specific path by setting the `CHROME_TRACE_FILE` env variable:
+```shell
+CHROME_TRACE_FILE = ~/Desktop/trace.json cargo run
+```
+
+If you cannot find your trace file, there may have been a permission issue when trying to generate your file. Be sure to check your cargo manifest directory!
+
+Once your file is generated, you can view it in Google Chrome at either [ui.perfetto.dev](ui.perfetto.dev) (new) or [chrome://trace](chrome://trace) (old).
+
+<p align="center">
+ <img alt="The native target" src="../docs/images/perfetto.png" width="80%">
+</p> \ No newline at end of file
diff --git a/profiling/src/lib.rs b/profiling/src/lib.rs
new file mode 100644
index 00000000..8fc58fb8
--- /dev/null
+++ b/profiling/src/lib.rs
@@ -0,0 +1,100 @@
+use std::time::Duration;
+use tracing_subscriber::prelude::*;
+use tracing_subscriber::Registry;
+
+#[cfg(feature = "tracing-chrome")]
+use {
+ tracing_chrome::FlushGuard,
+ tracing_subscriber::fmt::{format::DefaultFields, FormattedFields},
+};
+
+pub use tracing::{info_span, instrument};
+
+/// Profiler state. This will likely need to be updated or reworked when adding new tracing backends.
+pub struct Profiler {
+ #[cfg(feature = "tracing-chrome")]
+ /// [`FlushGuard`] must not be dropped until the application scope is dropped for accurate tracing.
+ _guard: FlushGuard,
+}
+
+pub fn init() -> Profiler {
+ // Registry stores the spans & generates unique span IDs
+ let subscriber = Registry::default();
+
+ #[cfg(feature = "tracing-chrome")]
+ let (chrome_layer, guard) = {
+ let mut layer = tracing_chrome::ChromeLayerBuilder::new();
+
+ // Optional configurable env var: CHROME_TRACE_FILE=/path/to/trace_file/file.json,
+ // for uploading to chrome://tracing (old) or ui.perfetto.dev (new).
+ if let Ok(path) = std::env::var("CHROME_TRACE_FILE") {
+ layer = layer.file(path);
+ } else if let Ok(current_dir) = std::env::current_dir() {
+ let time = std::time::SystemTime::now()
+ .duration_since(std::time::UNIX_EPOCH)
+ .unwrap_or(Duration::from_millis(0))
+ .as_millis();
+
+ let trace_file_name = current_dir
+ .file_name()
+ .map(|file_dir| {
+ format!(
+ "{}_trace_{}.json",
+ file_dir.to_str().unwrap_or("trace"),
+ time
+ )
+ })
+ .unwrap_or_else(|| "trace.json".to_string());
+
+ let path = format!(
+ "{}/{}",
+ current_dir.to_str().expect("Invalid path"),
+ trace_file_name
+ );
+
+ layer = layer.file(path);
+ } else {
+ layer = layer.file(env!("CARGO_MANIFEST_DIR"))
+ }
+
+ let (chrome_layer, guard) = layer
+ .name_fn(Box::new(|event_or_span| match event_or_span {
+ tracing_chrome::EventOrSpan::Event(event) => {
+ event.metadata().name().into()
+ }
+ tracing_chrome::EventOrSpan::Span(span) => {
+ if let Some(fields) = span
+ .extensions()
+ .get::<FormattedFields<DefaultFields>>()
+ {
+ format!(
+ "{}: {}",
+ span.metadata().name(),
+ fields.fields.as_str()
+ )
+ } else {
+ span.metadata().name().into()
+ }
+ }
+ }))
+ .build();
+
+ (chrome_layer, guard)
+ };
+
+ let fmt_layer = tracing_subscriber::fmt::Layer::default();
+ let subscriber = subscriber.with(fmt_layer);
+
+ #[cfg(feature = "tracing-chrome")]
+ let subscriber = subscriber.with(chrome_layer);
+
+ // create dispatcher which will forward span events to the subscriber
+ // this can only be set once or will panic
+ tracing::subscriber::set_global_default(subscriber)
+ .expect("Profiler could not set the global default subscriber.");
+
+ Profiler {
+ #[cfg(feature = "tracing-chrome")]
+ _guard: guard,
+ }
+}