diff options
Diffstat (limited to '')
| -rw-r--r-- | winit/src/application.rs | 66 | ||||
| -rw-r--r-- | winit/src/application/profiler.rs | 101 | ||||
| -rw-r--r-- | winit/src/lib.rs | 2 | 
3 files changed, 157 insertions, 12 deletions
diff --git a/winit/src/application.rs b/winit/src/application.rs index 1973fdce..74c73815 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -1,4 +1,6 @@  //! Create interactive, native cross-platform applications. +#[cfg(feature = "trace")] +mod profiler;  mod state;  pub use state::State; @@ -24,6 +26,11 @@ pub use iced_native::application::{Appearance, StyleSheet};  use std::mem::ManuallyDrop; +#[cfg(feature = "trace")] +pub use profiler::Profiler; +#[cfg(feature = "trace")] +use tracing::{info_span, instrument::Instrument}; +  /// An interactive, native cross-platform application.  ///  /// This trait is the main entrypoint of Iced. Once implemented, you can run @@ -111,9 +118,15 @@ where      use futures::Future;      use winit::event_loop::EventLoopBuilder; +    #[cfg(feature = "trace")] +    let _guard = Profiler::init(); +      let mut debug = Debug::new();      debug.startup_started(); +    #[cfg(feature = "trace")] +    let _ = info_span!("Application", "RUN").entered(); +      let event_loop = EventLoopBuilder::with_user_event().build();      let proxy = event_loop.create_proxy(); @@ -175,18 +188,26 @@ where      let (mut sender, receiver) = mpsc::unbounded(); -    let mut instance = Box::pin(run_instance::<A, E, C>( -        application, -        compositor, -        renderer, -        runtime, -        proxy, -        debug, -        receiver, -        init_command, -        window, -        settings.exit_on_close_request, -    )); +    let mut instance = Box::pin({ +        let run_instance = run_instance::<A, E, C>( +            application, +            compositor, +            renderer, +            runtime, +            proxy, +            debug, +            receiver, +            init_command, +            window, +            settings.exit_on_close_request, +        ); + +        #[cfg(feature = "trace")] +        let run_instance = +            run_instance.instrument(info_span!("Application", "LOOP")); + +        run_instance +    });      let mut context = task::Context::from_waker(task::noop_waker_ref()); @@ -391,6 +412,9 @@ async fn run_instance<A, E, C>(                  messages.push(message);              }              event::Event::RedrawRequested(_) => { +                #[cfg(feature = "trace")] +                let _ = info_span!("Application", "FRAME").entered(); +                  let physical_size = state.physical_size();                  if physical_size.width == 0 || physical_size.height == 0 { @@ -529,12 +553,24 @@ pub fn build_user_interface<'a, A: Application>(  where      <A::Renderer as crate::Renderer>::Theme: StyleSheet,  { +    #[cfg(feature = "trace")] +    let view_span = info_span!("Application", "VIEW").entered(); +      debug.view_started();      let view = application.view(); + +    #[cfg(feature = "trace")] +    let _ = view_span.exit();      debug.view_finished(); +    #[cfg(feature = "trace")] +    let layout_span = info_span!("Application", "LAYOUT").entered(); +      debug.layout_started();      let user_interface = UserInterface::build(view, size, cache, renderer); + +    #[cfg(feature = "trace")] +    let _ = layout_span.exit();      debug.layout_finished();      user_interface @@ -559,10 +595,16 @@ pub fn update<A: Application, E: Executor>(      <A::Renderer as crate::Renderer>::Theme: StyleSheet,  {      for message in messages.drain(..) { +        #[cfg(feature = "trace")] +        let update_span = info_span!("Application", "UPDATE").entered(); +          debug.log_message(&message);          debug.update_started();          let command = runtime.enter(|| application.update(message)); + +        #[cfg(feature = "trace")] +        let _ = update_span.exit();          debug.update_finished();          run_command( diff --git a/winit/src/application/profiler.rs b/winit/src/application/profiler.rs new file mode 100644 index 00000000..23eaa390 --- /dev/null +++ b/winit/src/application/profiler.rs @@ -0,0 +1,101 @@ +//! A simple profiler for Iced. +use std::ffi::OsStr; +use std::path::Path; +use std::time::Duration; +use tracing_subscriber::prelude::*; +use tracing_subscriber::Registry; +#[cfg(feature = "chrome-trace")] +use { +    tracing_chrome::FlushGuard, +    tracing_subscriber::fmt::{format::DefaultFields, FormattedFields}, +}; + +/// Profiler state. This will likely need to be updated or reworked when adding new tracing backends. +#[allow(missing_debug_implementations)] +pub struct Profiler { +    #[cfg(feature = "chrome-trace")] +    /// [`FlushGuard`] must not be dropped until the application scope is dropped for accurate tracing. +    _guard: FlushGuard, +} + +impl Profiler { +    /// Initializes the [`Profiler`]. +    pub fn init() -> Self { +        // Registry stores the spans & generates unique span IDs +        let subscriber = Registry::default(); + +        let default_path = Path::new(env!("CARGO_MANIFEST_DIR")); +        let curr_exe = std::env::current_exe() +            .unwrap_or_else(|_| default_path.to_path_buf()); +        let out_dir = curr_exe.parent().unwrap_or(default_path).join("traces"); + +        #[cfg(feature = "chrome-trace")] +        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 std::fs::create_dir_all(&out_dir).is_ok() { +                let time = std::time::SystemTime::now() +                    .duration_since(std::time::UNIX_EPOCH) +                    .unwrap_or(Duration::from_millis(0)) +                    .as_millis(); + +                let curr_exe_name = curr_exe +                    .file_name() +                    .unwrap_or_else(|| OsStr::new("trace")) +                    .to_str() +                    .unwrap_or("trace"); + +                let path = out_dir +                    .join(format!("{}_trace_{}.json", curr_exe_name, time)); + +                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 = "chrome-trace")] +        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("Tracer could not set the global default subscriber."); + +        Profiler { +            #[cfg(feature = "chrome-trace")] +            _guard: guard, +        } +    } +} diff --git a/winit/src/lib.rs b/winit/src/lib.rs index b8ed492d..06674109 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -51,6 +51,8 @@ mod proxy;  #[cfg(feature = "application")]  pub use application::Application; +#[cfg(feature = "trace")] +pub use application::Profiler;  pub use clipboard::Clipboard;  pub use error::Error;  pub use position::Position;  | 
