From 991c9ec441711a4c0b10ce595f3025f430123800 Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Thu, 22 Feb 2024 10:59:52 -0800 Subject: [PATCH] Integrate profiling into gpui (#8176) [Profiling](https://crates.io/crates/profiling) crate allows easy integration with various profiler tools. The best thing is - annotations compile to nothing unless you request a specific feature. For example, I used this command to enable Tracy support: ```bash cargo run --features profiling/profile-with-tracy ``` At the same time I had Tracy tool open and waiting for connection. It gathered nice stats from the run: ![zed-profiler](https://github.com/zed-industries/zed/assets/107301/5233045d-078c-4ad8-8b00-7ae55cf94ebb) Release Notes: - N/A --- Cargo.lock | 21 +++++++++++++++++++ Cargo.toml | 1 + crates/gpui/Cargo.toml | 1 + crates/gpui/src/platform/blade/blade_atlas.rs | 1 + crates/gpui/src/platform/blade/blade_belt.rs | 1 + .../gpui/src/platform/blade/blade_renderer.rs | 8 ++++++- crates/gpui/src/platform/linux/dispatcher.rs | 1 + crates/gpui/src/platform/linux/x11/client.rs | 8 ++++++- crates/gpui/src/window.rs | 4 ++++ crates/zed/Cargo.toml | 1 + 10 files changed, 45 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 62f9781cee..0f0546005b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4121,6 +4121,7 @@ dependencies = [ "pathfinder_geometry", "png", "postage", + "profiling", "rand 0.8.5", "raw-window-handle 0.5.2", "raw-window-handle 0.6.0", @@ -6863,6 +6864,25 @@ dependencies = [ "winapi 0.3.9", ] +[[package]] +name = "profiling" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d84d1d7a6ac92673717f9f6d1518374ef257669c24ebc5ac25d5033828be58" +dependencies = [ + "profiling-procmacros", +] + +[[package]] +name = "profiling-procmacros" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8021cf59c8ec9c432cfc2526ac6b8aa508ecaf29cd415f271b8406c1b851c3fd" +dependencies = [ + "quote", + "syn 2.0.48", +] + [[package]] name = "project" version = "0.1.0" @@ -11978,6 +11998,7 @@ dependencies = [ "outline", "parking_lot 0.11.2", "postage", + "profiling", "project", "project_panel", "project_symbols", diff --git a/Cargo.toml b/Cargo.toml index 17029e7779..457d8d9f3c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -203,6 +203,7 @@ linkify = "0.10.0" log = { version = "0.4.16", features = ["kv_unstable_serde"] } ordered-float = "2.1.1" parking_lot = "0.11.1" +profiling = "1" postage = { version = "0.5", features = ["futures-traits"] } pretty_assertions = "1.3.0" prost = "0.8" diff --git a/crates/gpui/Cargo.toml b/crates/gpui/Cargo.toml index dcb309eb06..a8b49ce96b 100644 --- a/crates/gpui/Cargo.toml +++ b/crates/gpui/Cargo.toml @@ -51,6 +51,7 @@ parking = "2.0.0" parking_lot.workspace = true pathfinder_geometry = "0.5" postage.workspace = true +profiling.workspace = true rand.workspace = true raw-window-handle = "0.6" refineable.workspace = true diff --git a/crates/gpui/src/platform/blade/blade_atlas.rs b/crates/gpui/src/platform/blade/blade_atlas.rs index ccebc93b30..18c8a607b1 100644 --- a/crates/gpui/src/platform/blade/blade_atlas.rs +++ b/crates/gpui/src/platform/blade/blade_atlas.rs @@ -117,6 +117,7 @@ impl PlatformAtlas for BladeAtlas { if let Some(tile) = lock.tiles_by_key.get(key) { Ok(tile.clone()) } else { + profiling::scope!("new tile"); let (size, bytes) = build()?; let tile = lock.allocate(size, key.texture_kind()); lock.upload_texture(tile.texture_id, tile.bounds, &bytes); diff --git a/crates/gpui/src/platform/blade/blade_belt.rs b/crates/gpui/src/platform/blade/blade_belt.rs index 88f8cf8d80..322caaa3ee 100644 --- a/crates/gpui/src/platform/blade/blade_belt.rs +++ b/crates/gpui/src/platform/blade/blade_belt.rs @@ -39,6 +39,7 @@ impl BladeBelt { } } + #[profiling::function] pub fn alloc(&mut self, size: u64, gpu: &gpu::Context) -> gpu::BufferPiece { for &mut (ref rb, ref mut offset) in self.active.iter_mut() { let aligned = offset.next_multiple_of(self.desc.alignment); diff --git a/crates/gpui/src/platform/blade/blade_renderer.rs b/crates/gpui/src/platform/blade/blade_renderer.rs index d715bed895..39064f4ffd 100644 --- a/crates/gpui/src/platform/blade/blade_renderer.rs +++ b/crates/gpui/src/platform/blade/blade_renderer.rs @@ -444,6 +444,7 @@ impl BladeRenderer { self.gpu.metal_layer().unwrap().as_ptr() } + #[profiling::function] fn rasterize_paths(&mut self, paths: &[Path]) { self.path_tiles.clear(); let mut vertices_by_texture_id = HashMap::default(); @@ -506,7 +507,10 @@ impl BladeRenderer { } pub fn draw(&mut self, scene: &Scene) { - let frame = self.gpu.acquire_frame(); + let frame = { + profiling::scope!("acquire frame"); + self.gpu.acquire_frame() + }; self.command_encoder.start(); self.command_encoder.init_texture(frame.texture()); @@ -529,6 +533,7 @@ impl BladeRenderer { }], depth_stencil: None, }) { + profiling::scope!("render pass"); for batch in scene.batches() { match batch { PrimitiveBatch::Quads(quads) => { @@ -718,6 +723,7 @@ impl BladeRenderer { self.command_encoder.present(frame); let sync_point = self.gpu.submit(&mut self.command_encoder); + profiling::scope!("finish"); self.instance_belt.flush(&sync_point); self.atlas.after_frame(&sync_point); self.atlas.clear_textures(AtlasTextureKind::Path); diff --git a/crates/gpui/src/platform/linux/dispatcher.rs b/crates/gpui/src/platform/linux/dispatcher.rs index bb96da6a8b..26301ad95a 100644 --- a/crates/gpui/src/platform/linux/dispatcher.rs +++ b/crates/gpui/src/platform/linux/dispatcher.rs @@ -33,6 +33,7 @@ impl LinuxDispatcher { ) -> Self { let (background_sender, background_receiver) = flume::unbounded::(); let background_thread = thread::spawn(move || { + profiling::register_thread!("background"); for runnable in background_receiver { let _ignore_panic = panic::catch_unwind(|| runnable.run()); } diff --git a/crates/gpui/src/platform/linux/x11/client.rs b/crates/gpui/src/platform/linux/x11/client.rs index 1428654d8d..250305e780 100644 --- a/crates/gpui/src/platform/linux/x11/client.rs +++ b/crates/gpui/src/platform/linux/x11/client.rs @@ -71,7 +71,10 @@ impl Client for X11Client { // into window functions as they may invoke callbacks that need // to immediately access the platform (self). while !self.platform_inner.state.lock().quit_requested { - let event = self.xcb_connection.wait_for_event().unwrap(); + let event = { + profiling::scope!("Wait for event"); + self.xcb_connection.wait_for_event().unwrap() + }; match event { xcb::Event::X(x::Event::ClientMessage(ev)) => { if let x::ClientMessageData::Data32([atom, ..]) = ev.data() { @@ -210,6 +213,7 @@ impl Client for X11Client { _ => {} } + profiling::scope!("Runnables"); if let Ok(runnable) = self.platform_inner.main_receiver.try_recv() { runnable.run(); } @@ -219,6 +223,7 @@ impl Client for X11Client { fun(); } } + fn displays(&self) -> Vec> { let setup = self.xcb_connection.get_setup(); setup @@ -230,6 +235,7 @@ impl Client for X11Client { }) .collect() } + fn display(&self, id: DisplayId) -> Option> { Some(Rc::new(X11Display::new(&self.xcb_connection, id.0 as i32))) } diff --git a/crates/gpui/src/window.rs b/crates/gpui/src/window.rs index 47cab51910..0a45934ad2 100644 --- a/crates/gpui/src/window.rs +++ b/crates/gpui/src/window.rs @@ -950,6 +950,7 @@ impl<'a> WindowContext<'a> { /// Produces a new frame and assigns it to `rendered_frame`. To actually show /// the contents of the new [Scene], use [present]. + #[profiling::function] pub fn draw(&mut self) { self.window.dirty.set(false); self.window.drawing = true; @@ -1092,11 +1093,13 @@ impl<'a> WindowContext<'a> { self.window.needs_present.set(true); } + #[profiling::function] fn present(&self) { self.window .platform_window .draw(&self.window.rendered_frame.scene); self.window.needs_present.set(false); + profiling::finish_frame!(); } /// Dispatch a given keystroke as though the user had typed it. @@ -1132,6 +1135,7 @@ impl<'a> WindowContext<'a> { } /// Dispatch a mouse or keyboard event on the window. + #[profiling::function] pub fn dispatch_event(&mut self, event: PlatformInput) -> bool { self.window.last_input_timestamp.set(Instant::now()); // Handlers may set this to false by calling `stop_propagation`. diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 92e0f43167..74e010b152 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -77,6 +77,7 @@ num_cpus = "1.13.0" outline.workspace = true parking_lot.workspace = true postage.workspace = true +profiling.workspace = true project.workspace = true project_panel.workspace = true project_symbols.workspace = true