From ccad3cf0fbe74c8cd5f8915bdb85dad8f1f33614 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sun, 15 Sep 2024 18:08:54 +0200 Subject: [PATCH] all: use tracy for tracing --- Cargo.lock | 73 +++--- Cargo.toml | 9 + src/acceptor.rs | 18 +- src/async_engine.rs | 11 +- src/async_engine/ae_task.rs | 11 +- src/backends/metal.rs | 12 +- src/backends/metal/present.rs | 5 + src/backends/metal/video.rs | 17 +- src/backends/x.rs | 17 +- src/client.rs | 2 +- src/client/tasks.rs | 11 +- src/clientmem.rs | 1 + src/compositor.rs | 82 +++++-- src/config/handler.rs | 4 +- src/cpu_worker.rs | 16 +- src/cpu_worker/jobs/img_copy.rs | 1 + src/cpu_worker/jobs/read_write.rs | 2 +- src/cpu_worker/tests.rs | 6 +- src/dbus/auth.rs | 8 +- src/dbus/holder.rs | 2 +- src/ei/ei_acceptor.rs | 7 +- src/ei/ei_client.rs | 4 +- src/ei/ei_client/ei_tasks.rs | 11 +- src/forker.rs | 25 ++- src/gfx_apis/vulkan/allocator.rs | 2 + src/gfx_apis/vulkan/renderer.rs | 34 ++- src/gfx_apis/vulkan/semaphore.rs | 1 + src/gfx_apis/vulkan/shm_image.rs | 23 +- src/ifs/ext_idle_notifier_v1.rs | 6 +- src/ifs/wl_seat.rs | 2 +- .../ops/read_write_no_cancel/tests.rs | 4 +- src/it.rs | 2 +- src/it/test_backend.rs | 2 +- src/it/test_transport.rs | 2 + src/main.rs | 2 + src/pipewire/pw_con.rs | 8 +- src/pipewire/pw_ifs/pw_client_node.rs | 4 +- src/portal.rs | 9 +- src/portal/ptr_gui.rs | 10 +- src/security_context_acceptor.rs | 16 +- src/sighand.rs | 2 +- src/state.rs | 2 +- src/tasks/connector.rs | 7 +- src/tasks/drmdev.rs | 2 +- src/tasks/input_device.rs | 2 +- src/tools/tool_client.rs | 6 +- src/tracy.rs | 15 ++ src/tracy/tracy_impl.rs | 212 ++++++++++++++++++ src/tracy/tracy_noop.rs | 51 +++++ src/utils/run_toplevel.rs | 2 +- src/video/drm/wait_for_sync_obj.rs | 2 +- src/wheel.rs | 2 +- src/wl_usr.rs | 2 + src/xcon.rs | 12 +- src/xwayland.rs | 6 +- src/xwayland/xwm.rs | 11 +- 56 files changed, 647 insertions(+), 171 deletions(-) create mode 100644 src/tracy.rs create mode 100644 src/tracy/tracy_impl.rs create mode 100644 src/tracy/tracy_noop.rs diff --git a/Cargo.lock b/Cargo.lock index 0f8b870b..f9cdd5a8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -210,7 +210,7 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.0", + "windows-targets 0.52.6", ] [[package]] @@ -584,10 +584,12 @@ dependencies = [ "png", "rand", "repc", + "rustc-demangle", "serde", "shaderc", "smallvec", "thiserror", + "tracy-client-sys", "uapi", ] @@ -1005,9 +1007,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustix" @@ -1274,6 +1276,14 @@ dependencies = [ "serde_yaml", ] +[[package]] +name = "tracy-client-sys" +version = "0.24.0" +source = "git+https://github.com/mahkoh/rust_tracy_client.git?branch=jorth/debuginfod#0ffd3d3375039aa984189daf776f633312e890c8" +dependencies = [ + "cc", +] + [[package]] name = "uapi" version = "0.2.13" @@ -1431,7 +1441,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", ] [[package]] @@ -1449,7 +1459,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", ] [[package]] @@ -1469,17 +1479,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -1490,9 +1501,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -1502,9 +1513,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -1514,9 +1525,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -1526,9 +1543,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -1538,9 +1555,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -1550,9 +1567,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -1562,9 +1579,9 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "xmlparser" diff --git a/Cargo.toml b/Cargo.toml index 1f941b30..a7016682 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -58,6 +58,14 @@ gpu-alloc-ash = "0.7.0" serde = { version = "1.0.196", features = ["derive"] } enum-map = "2.7.3" png = "0.17.13" +rustc-demangle = { version = "0.1.24", optional = true } + +[dependencies.tracy-client-sys] +version = "0.24.0" +git = "https://github.com/mahkoh/rust_tracy_client.git" +branch = "jorth/debuginfod" +features = ["ondemand", "manual-lifetime"] +optional = true [build-dependencies] repc = "0.1.1" @@ -78,3 +86,4 @@ opt-level = 3 [features] rc_tracking = [] it = [] +tracy = ["dep:tracy-client-sys", "dep:rustc-demangle"] diff --git a/src/acceptor.rs b/src/acceptor.rs index 4fa6f13d..9959f74d 100644 --- a/src/acceptor.rs +++ b/src/acceptor.rs @@ -146,16 +146,14 @@ impl Acceptor { } let acc = Rc::new(Acceptor { socket }); let futures = vec![ - state.eng.spawn(accept( - acc.socket.secure.clone(), - state.clone(), - ClientCaps::all(), - )), - state.eng.spawn(accept( - acc.socket.insecure.clone(), - state.clone(), - CAPS_DEFAULT, - )), + state.eng.spawn( + "secure acceptor", + accept(acc.socket.secure.clone(), state.clone(), ClientCaps::all()), + ), + state.eng.spawn( + "insecure acceptor", + accept(acc.socket.insecure.clone(), state.clone(), CAPS_DEFAULT), + ), ]; state.acceptor.set(Some(acc.clone())); Ok((acc, futures)) diff --git a/src/async_engine.rs b/src/async_engine.rs index 4ba01f11..ca118545 100644 --- a/src/async_engine.rs +++ b/src/async_engine.rs @@ -64,16 +64,21 @@ impl AsyncEngine { } } - pub fn spawn + 'static>(self: &Rc, f: F) -> SpawnedFuture { - self.spawn_(Phase::EventHandling, f) + pub fn spawn + 'static>( + self: &Rc, + name: &str, + f: F, + ) -> SpawnedFuture { + self.spawn_(name, Phase::EventHandling, f) } pub fn spawn2 + 'static>( self: &Rc, + name: &str, phase: Phase, f: F, ) -> SpawnedFuture { - self.spawn_(phase, f) + self.spawn_(name, phase, f) } pub fn yield_now(self: &Rc) -> Yield { diff --git a/src/async_engine/ae_task.rs b/src/async_engine/ae_task.rs index 769a97b1..51e24393 100644 --- a/src/async_engine/ae_task.rs +++ b/src/async_engine/ae_task.rs @@ -1,6 +1,7 @@ use { crate::{ async_engine::{AsyncEngine, Phase}, + tracy::ZoneName, utils::{ numcell::NumCell, ptr_ext::{MutPtrExt, PtrExt}, @@ -95,6 +96,8 @@ struct Task> { data: UnsafeCell>, waker: Cell>, queue: Rc, + #[cfg_attr(not(feature = "tracy"), expect(dead_code))] + zone: ZoneName, } pub(super) struct Runnable { @@ -122,6 +125,7 @@ impl Drop for Runnable { impl AsyncEngine { pub(super) fn spawn_>( self: &Rc, + #[cfg_attr(not(feature = "tracy"), expect(unused_variables))] name: &str, phase: Phase, f: F, ) -> SpawnedFuture { @@ -134,6 +138,7 @@ impl AsyncEngine { }), waker: Cell::new(None), queue: self.clone(), + zone: create_zone_name!("task:{}", name), }); unsafe { f.schedule_run(); @@ -229,7 +234,11 @@ impl> Task { let waker = Waker::from_raw(raw_waker); let mut ctx = Context::from_waker(&waker); - if let Poll::Ready(d) = Pin::new_unchecked(&mut *data.future).poll(&mut ctx) { + let poll = { + dynamic_zone!(self.zone); + Pin::new_unchecked(&mut *data.future).poll(&mut ctx) + }; + if let Poll::Ready(d) = poll { ManuallyDrop::drop(&mut data.future); ptr::write(&mut data.result, ManuallyDrop::new(d)); self.state.or_assign(COMPLETED); diff --git a/src/backends/metal.rs b/src/backends/metal.rs index 7843b5fe..23ed3466 100644 --- a/src/backends/metal.rs +++ b/src/backends/metal.rs @@ -163,8 +163,14 @@ impl Debug for MetalBackend { impl MetalBackend { async fn run(self: Rc) -> Result<(), MetalError> { - let _monitor = self.state.eng.spawn(self.clone().monitor_devices()); - let _events = self.state.eng.spawn(self.clone().handle_libinput_events()); + let _monitor = self + .state + .eng + .spawn("monitor devices", self.clone().monitor_devices()); + let _events = self.state.eng.spawn( + "handle libinput events", + self.clone().handle_libinput_events(), + ); if let Err(e) = self.enumerate_devices() { return Err(MetalError::Enumerate(Box::new(e))); } @@ -175,7 +181,7 @@ impl MetalBackend { impl Backend for MetalBackend { fn run(self: Rc) -> SpawnedFuture>> { let slf = self.clone(); - self.state.eng.spawn(async move { + self.state.eng.spawn("metal backend", async move { slf.run().await?; Ok(()) }) diff --git a/src/backends/metal/present.rs b/src/backends/metal/present.rs index 8a5a66cc..6a5b7fbb 100644 --- a/src/backends/metal/present.rs +++ b/src/backends/metal/present.rs @@ -13,6 +13,7 @@ use { }, theme::Color, time::Time, + tracy::FrameName, tree::OutputNode, utils::{errorfmt::ErrorFmt, oserror::OsError, transform_ext::TransformExt}, video::{ @@ -90,6 +91,8 @@ impl MetalConnector { } pub async fn present_loop(self: Rc) { + #[cfg_attr(not(feature = "tracy"), expect(unused_variables))] + let frame_name = FrameName::get(&self.kernel_id().to_string()); let mut cur_sec = 0; let mut max = 0; loop { @@ -113,6 +116,7 @@ impl MetalConnector { expected_sequence += 1; } } + frame!(frame_name); if let Err(e) = self.present_once().await { log::error!("Could not present: {}", ErrorFmt(e)); continue; @@ -293,6 +297,7 @@ impl MetalConnector { cursor: Option<&CursorProgramming>, new_fb: Option<&PresentFb>, ) -> Result<(), MetalError> { + zone!("program_connector"); let mut changes = self.master.change(); let mut try_async_flip = self.try_async_flip(); macro_rules! change { diff --git a/src/backends/metal/video.rs b/src/backends/metal/video.rs index 672f6cd9..d1eb10a7 100644 --- a/src/backends/metal/video.rs +++ b/src/backends/metal/video.rs @@ -1089,10 +1089,11 @@ fn create_connector( presentation_is_zero_copy: Cell::new(false), }); let futures = ConnectorFutures { - _present: backend - .state - .eng - .spawn2(Phase::Present, slf.clone().present_loop()), + _present: backend.state.eng.spawn2( + "present loop", + Phase::Present, + slf.clone().present_loop(), + ), }; Ok((slf, futures)) } @@ -1791,10 +1792,10 @@ impl MetalBackend { } } - let drm_handler = self - .state - .eng - .spawn(self.clone().handle_drm_events(slf.clone())); + let drm_handler = self.state.eng.spawn( + "handle drm events", + self.clone().handle_drm_events(slf.clone()), + ); slf.dev.handle_events.handle_events.set(Some(drm_handler)); Ok(slf) diff --git a/src/backends/x.rs b/src/backends/x.rs index 2235a565..d19f999f 100644 --- a/src/backends/x.rs +++ b/src/backends/x.rs @@ -249,7 +249,7 @@ pub async fn create(state: &Rc) -> Result, XBackendError> { impl Backend for XBackend { fn run(self: Rc) -> SpawnedFuture>> { let slf = self.clone(); - self.state.eng.spawn(async move { + self.state.eng.spawn("x backend", async move { slf.run().await?; Ok(()) }) @@ -280,12 +280,19 @@ impl XBackend { async fn run(self: Rc) -> Result<(), XBackendError> { self.query_devices(INPUT_DEVICE_ALL_MASTER).await?; - let _events = self.state.eng.spawn(self.clone().event_handler()); - let _grab = self.state.eng.spawn(self.clone().grab_handler()); - let _present = self + let _events = self .state .eng - .spawn2(Phase::Present, self.clone().present_handler()); + .spawn("x event handler", self.clone().event_handler()); + let _grab = self + .state + .eng + .spawn("grab handler", self.clone().grab_handler()); + let _present = self.state.eng.spawn2( + "present handler", + Phase::Present, + self.clone().present_handler(), + ); self.state.set_render_ctx(Some(self.ctx.clone())); self.state diff --git a/src/client.rs b/src/client.rs index 1e798af0..7219806a 100644 --- a/src/client.rs +++ b/src/client.rs @@ -179,7 +179,7 @@ impl Clients { data.objects.display.set(Some(display.clone())); data.objects.add_client_object(display).expect(""); let client = ClientHolder { - _handler: global.eng.spawn(tasks::client(data.clone())), + _handler: global.eng.spawn("client", tasks::client(data.clone())), data: data.clone(), }; log::info!( diff --git a/src/client/tasks.rs b/src/client/tasks.rs index f06bf75e..04fff297 100644 --- a/src/client/tasks.rs +++ b/src/client/tasks.rs @@ -14,9 +14,16 @@ use { }; pub async fn client(data: Rc) { - let mut recv = data.state.eng.spawn(receive(data.clone())).fuse(); + let mut recv = data + .state + .eng + .spawn("client receive", receive(data.clone())) + .fuse(); let mut shutdown = data.shutdown.triggered().fuse(); - let _send = data.state.eng.spawn2(Phase::PostLayout, send(data.clone())); + let _send = data + .state + .eng + .spawn2("client send", Phase::PostLayout, send(data.clone())); select! { _ = recv => { }, _ = shutdown => { }, diff --git a/src/clientmem.rs b/src/clientmem.rs index 3f435e0c..1255ee22 100644 --- a/src/clientmem.rs +++ b/src/clientmem.rs @@ -255,6 +255,7 @@ impl CpuJob for CloseMemWork { impl CpuWork for CloseMemWork { fn run(&mut self) -> Option> { + zone!("CloseMemWork"); self.fd.take(); unsafe { c::munmap(self.data as _, self.data.len()); diff --git a/src/compositor.rs b/src/compositor.rs index 43fea12d..c3bc5fc4 100644 --- a/src/compositor.rs +++ b/src/compositor.rs @@ -33,6 +33,7 @@ use { sighand::{self, SighandError}, state::{ConnectorData, IdleState, ScreenlockState, State, XWaylandState}, tasks::{self, idle}, + tracy::enable_profiler, tree::{ container_layout, container_render_data, float_layout, float_titles, output_render_data, DisplayNode, NodeIds, OutputNode, TearingMode, VrrMode, @@ -62,6 +63,7 @@ pub const MAX_EXTENTS: i32 = (1 << 22) - 1; pub fn start_compositor(global: GlobalArgs, args: RunArgs) { let forker = create_forker(); let portal = portal::run_from_compositor(global.log_level.into()); + enable_profiler(); let logger = Logger::install_compositor(global.log_level.into()); let portal = match portal { Ok(p) => Some(p), @@ -279,9 +281,12 @@ fn start_compositor2( } let mut _portal = None; if let (Some(portal), Some(logger)) = (portal, &logger) { - _portal = Some(engine.spawn(portal.spawn(engine.clone(), ring.clone(), logger.clone()))); + _portal = Some(engine.spawn( + "portal", + portal.spawn(engine.clone(), ring.clone(), logger.clone()), + )); } - let _compositor = engine.spawn(start_compositor3(state.clone(), test_future)); + let _compositor = engine.spawn("compositor", start_compositor3(state.clone(), test_future)); ring.run()?; state.clear(); Ok(()) @@ -354,20 +359,65 @@ fn start_global_event_handlers( let eng = &state.eng; vec![ - eng.spawn(tasks::handle_backend_events(state.clone())), - eng.spawn(tasks::handle_slow_clients(state.clone())), - eng.spawn(tasks::handle_hardware_cursor_tick(state.clone())), - eng.spawn2(Phase::Layout, container_layout(state.clone())), - eng.spawn2(Phase::PostLayout, container_render_data(state.clone())), - eng.spawn2(Phase::PostLayout, output_render_data(state.clone())), - eng.spawn2(Phase::Layout, float_layout(state.clone())), - eng.spawn2(Phase::PostLayout, float_titles(state.clone())), - eng.spawn2(Phase::PostLayout, idle(state.clone(), backend.clone())), - eng.spawn2(Phase::PostLayout, input_popup_positioning(state.clone())), - eng.spawn2(Phase::Present, perform_toplevel_screencasts(state.clone())), - eng.spawn2(Phase::PostLayout, perform_screencast_realloc(state.clone())), - eng.spawn2(Phase::PostLayout, visualize_damage(state.clone())), - eng.spawn(tasks::handle_slow_ei_clients(state.clone())), + eng.spawn( + "backend events", + tasks::handle_backend_events(state.clone()), + ), + eng.spawn("slow client", tasks::handle_slow_clients(state.clone())), + eng.spawn( + "handware cursor tick", + tasks::handle_hardware_cursor_tick(state.clone()), + ), + eng.spawn2( + "container layout", + Phase::Layout, + container_layout(state.clone()), + ), + eng.spawn2( + "container render", + Phase::PostLayout, + container_render_data(state.clone()), + ), + eng.spawn2( + "output render", + Phase::PostLayout, + output_render_data(state.clone()), + ), + eng.spawn2("float layout", Phase::Layout, float_layout(state.clone())), + eng.spawn2( + "float titles", + Phase::PostLayout, + float_titles(state.clone()), + ), + eng.spawn2( + "idle", + Phase::PostLayout, + idle(state.clone(), backend.clone()), + ), + eng.spawn2( + "input, popup positioning", + Phase::PostLayout, + input_popup_positioning(state.clone()), + ), + eng.spawn2( + "toplevel screencast present", + Phase::Present, + perform_toplevel_screencasts(state.clone()), + ), + eng.spawn2( + "screencast realloc", + Phase::PostLayout, + perform_screencast_realloc(state.clone()), + ), + eng.spawn2( + "visualize damage", + Phase::PostLayout, + visualize_damage(state.clone()), + ), + eng.spawn( + "slow ei clients", + tasks::handle_slow_ei_clients(state.clone()), + ), ] } diff --git a/src/config/handler.rs b/src/config/handler.rs index 987d0a15..418d10c6 100644 --- a/src/config/handler.rs +++ b/src/config/handler.rs @@ -447,7 +447,7 @@ impl ConfigProxyHandler { let handler = { let timer = timer.clone(); let slf = self.clone(); - self.state.eng.spawn(async move { + self.state.eng.spawn("config timer", async move { loop { match timer.expired(&slf.state.ring).await { Ok(_) => slf.send(&ServerMessage::TimerExpired { @@ -1400,7 +1400,7 @@ impl ConfigProxyHandler { let slf = self.clone(); let trigger = event.clone(); let fd = fd.clone(); - let future = self.state.eng.spawn(async move { + let future = self.state.eng.spawn("config fd poller", async move { loop { trigger.triggered().await; let res = slf.state.ring.poll(&fd, events).await.merge(); diff --git a/src/cpu_worker.rs b/src/cpu_worker.rs index ec360aa0..a17888b7 100644 --- a/src/cpu_worker.rs +++ b/src/cpu_worker.rs @@ -283,8 +283,11 @@ impl CpuWorker { pending_job_data_cache: Default::default(), }); Ok(Self { - _completions_listener: eng.spawn(data.clone().wait_for_completions()), - _job_enqueuer: eng.spawn(data.clone().equeue_jobs()), + _completions_listener: eng.spawn( + "cpu worker completions", + data.clone().wait_for_completions(), + ), + _job_enqueuer: eng.spawn("cpu worker enqueue", data.clone().equeue_jobs()), data, }) } @@ -325,10 +328,13 @@ fn work( async_jobs: Default::default(), stopped: Cell::new(false), }); - let _stop_listener = worker.eng.spawn(worker.clone().handle_stop(stop)); - let _new_job_listener = worker + let _stop_listener = worker .eng - .spawn(worker.clone().handle_new_jobs(new_jobs, have_new_jobs)); + .spawn("stop listener", worker.clone().handle_stop(stop)); + let _new_job_listener = worker.eng.spawn( + "new job listener", + worker.clone().handle_new_jobs(new_jobs, have_new_jobs), + ); if let Err(e) = worker.ring.run() { panic!("io_uring failed: {}", ErrorFmt(e)); } diff --git a/src/cpu_worker/jobs/img_copy.rs b/src/cpu_worker/jobs/img_copy.rs index 414c1afe..6f7391c7 100644 --- a/src/cpu_worker/jobs/img_copy.rs +++ b/src/cpu_worker/jobs/img_copy.rs @@ -35,6 +35,7 @@ impl ImgCopyWork { impl CpuWork for ImgCopyWork { fn run(&mut self) -> Option> { + zone!("ImgCopyWork"); for rect in &self.rects { let mut offset = rect.y1() * self.stride + rect.x1() * self.bpp; if rect.width() == self.width { diff --git a/src/cpu_worker/jobs/read_write.rs b/src/cpu_worker/jobs/read_write.rs index 791ee22f..2b0e2a19 100644 --- a/src/cpu_worker/jobs/read_write.rs +++ b/src/cpu_worker/jobs/read_write.rs @@ -102,7 +102,7 @@ impl AsyncCpuWork for ReadWriteWorkConfig { completion: WorkCompletion, ) -> SpawnedFuture { let ring = ring.clone(); - eng.spawn(async move { + eng.spawn("shm read/write", async move { let res = loop { if self.cancel.cancelled.load(Relaxed) { break Err(ReadWriteJobError::Cancelled); diff --git a/src/cpu_worker/tests.rs b/src/cpu_worker/tests.rs index 6b0bb826..3b50135a 100644 --- a/src/cpu_worker/tests.rs +++ b/src/cpu_worker/tests.rs @@ -62,7 +62,7 @@ impl AsyncCpuWork for AsyncWork { completion: WorkCompletion, ) -> SpawnedFuture { let ring = ring.clone(); - eng.spawn(async move { + eng.spawn("", async move { let mut buf = [0; 8]; let res = ring .read_no_cancel(self.0.borrow(), 0, &mut buf, |_| ()) @@ -90,7 +90,7 @@ fn run(cancel: bool) { work: Work(eventfd.clone()), cancel, })); - let _fut1 = eng.spawn(async move { + let _fut1 = eng.spawn("", async move { wheel.timeout(1).await.unwrap(); if cancel { drop(pending_job); @@ -99,7 +99,7 @@ fn run(cancel: bool) { pending::<()>().await; } }); - let _fut2 = eng.spawn(async move { + let _fut2 = eng.spawn("", async move { ae.triggered().await; ring2.stop(); }); diff --git a/src/dbus/auth.rs b/src/dbus/auth.rs index 56bdfc46..158c5239 100644 --- a/src/dbus/auth.rs +++ b/src/dbus/auth.rs @@ -39,10 +39,14 @@ impl Auth { } log::info!("{}: Authenticated", self.socket.bus_name); self.socket.incoming.set(Some( - self.socket.eng.spawn(handle_incoming(self.socket.clone())), + self.socket + .eng + .spawn("dbus incoming", handle_incoming(self.socket.clone())), )); self.socket.outgoing_.set(Some( - self.socket.eng.spawn(handle_outgoing(self.socket.clone())), + self.socket + .eng + .spawn("dbus outgoing", handle_outgoing(self.socket.clone())), )); self.socket.auth.take(); } diff --git a/src/dbus/holder.rs b/src/dbus/holder.rs index 41d066a3..e9d617c0 100644 --- a/src/dbus/holder.rs +++ b/src/dbus/holder.rs @@ -84,7 +84,7 @@ async fn connect( } }, ); - let future = eng.spawn(handle_auth(socket.clone())); + let future = eng.spawn("dbus auth", handle_auth(socket.clone())); socket.auth.set(Some(future)); Ok(socket) } diff --git a/src/ei/ei_acceptor.rs b/src/ei/ei_acceptor.rs index b3b2d211..8f5a57b8 100644 --- a/src/ei/ei_acceptor.rs +++ b/src/ei/ei_acceptor.rs @@ -126,9 +126,10 @@ impl EiAcceptor { return Err(EiAcceptorError::ListenFailed(e.into())); } let acc = Rc::new(EiAcceptor { socket }); - let future = state - .eng - .spawn(accept(acc.socket.insecure.clone(), state.clone())); + let future = state.eng.spawn( + "ei accept", + accept(acc.socket.insecure.clone(), state.clone()), + ); Ok((acc, future)) } diff --git a/src/ei/ei_client.rs b/src/ei/ei_client.rs index 9d69e56c..a749682c 100644 --- a/src/ei/ei_client.rs +++ b/src/ei/ei_client.rs @@ -120,7 +120,9 @@ impl EiClients { handshake.send_handshake_version(); data.objects.add_handshake(&handshake); let client = EiClientHolder { - _handler: global.eng.spawn(ei_tasks::ei_client(data.clone())), + _handler: global + .eng + .spawn("ei client", ei_tasks::ei_client(data.clone())), data: data.clone(), }; log::info!( diff --git a/src/ei/ei_client/ei_tasks.rs b/src/ei/ei_client/ei_tasks.rs index bffa79f2..16d3b48b 100644 --- a/src/ei/ei_client/ei_tasks.rs +++ b/src/ei/ei_client/ei_tasks.rs @@ -16,9 +16,16 @@ use { }; pub async fn ei_client(data: Rc) { - let mut recv = data.state.eng.spawn(receive(data.clone())).fuse(); + let mut recv = data + .state + .eng + .spawn("ei receive", receive(data.clone())) + .fuse(); let mut shutdown = data.shutdown.triggered().fuse(); - let _send = data.state.eng.spawn2(Phase::PostLayout, send(data.clone())); + let _send = data + .state + .eng + .spawn2("ei send", Phase::PostLayout, send(data.clone())); select! { _ = recv => { }, _ = shutdown => { }, diff --git a/src/forker.rs b/src/forker.rs index 3d6a3508..44cbcb24 100644 --- a/src/forker.rs +++ b/src/forker.rs @@ -109,13 +109,20 @@ impl ForkerProxy { pub fn install(self: &Rc, state: &Rc) { state.forker.set(Some(self.clone())); - self.task_proc.set(Some( - state.eng.spawn(self.clone().check_process(state.clone())), + self.task_proc.set(Some(state.eng.spawn( + "forker check process", + self.clone().check_process(state.clone()), + ))); + self.task_in.set(Some( + state + .eng + .spawn("forker incoming", self.clone().incoming(state.clone())), + )); + self.task_out.set(Some( + state + .eng + .spawn("forker outgoing", self.clone().outgoing(state.clone())), )); - self.task_in - .set(Some(state.eng.spawn(self.clone().incoming(state.clone())))); - self.task_out - .set(Some(state.eng.spawn(self.clone().outgoing(state.clone())))); } pub fn setenv(&self, key: &[u8], val: &[u8]) { @@ -353,8 +360,8 @@ impl Forker { outgoing: Default::default(), pending_spawns: Default::default(), }); - let _f1 = ae.spawn(forker.clone().incoming()); - let _f2 = ae.spawn(forker.clone().outgoing()); + let _f1 = ae.spawn("forker incoming", forker.clone().incoming()); + let _f2 = ae.spawn("forker outgoing", forker.clone().outgoing()); let _ = ring.run(); std::process::exit(1); } @@ -462,7 +469,7 @@ impl Forker { } drop(write); let slf = self.clone(); - let spawn = self.ae.spawn(async move { + let spawn = self.ae.spawn("await spawn", async move { let read = Rc::new(read); if let Err(e) = slf.ring.readable(&read).await { log::error!( diff --git a/src/gfx_apis/vulkan/allocator.rs b/src/gfx_apis/vulkan/allocator.rs index 6cff0834..536e0667 100644 --- a/src/gfx_apis/vulkan/allocator.rs +++ b/src/gfx_apis/vulkan/allocator.rs @@ -251,6 +251,7 @@ struct AllocWork { impl CpuWork for AllocWork { fn run(&mut self) -> Option> { + zone!("AllocWork"); let r = do_alloc( &mut self.allocator.lock(), &self.device, @@ -303,6 +304,7 @@ struct FreeWork { impl CpuWork for FreeWork { fn run(&mut self) -> Option> { + zone!("FreeWork"); let ua = self.allocation.take().unwrap(); unsafe { do_free(&mut self.allocator.lock(), &self.device, ua.block, ua.ptr); diff --git a/src/gfx_apis/vulkan/renderer.rs b/src/gfx_apis/vulkan/renderer.rs index 7021744c..969cb448 100644 --- a/src/gfx_apis/vulkan/renderer.rs +++ b/src/gfx_apis/vulkan/renderer.rs @@ -274,6 +274,7 @@ impl VulkanRenderer { } fn collect_memory(&self, opts: &[GfxApiOpt]) { + zone!("collect_memory"); let mut memory = self.memory.borrow_mut(); memory.sample.clear(); for cmd in opts { @@ -296,6 +297,7 @@ impl VulkanRenderer { } fn begin_command_buffer(&self, buf: CommandBuffer) -> Result<(), VulkanError> { + zone!("begin_command_buffer"); let begin_info = CommandBufferBeginInfo::default().flags(CommandBufferUsageFlags::ONE_TIME_SUBMIT); unsafe { @@ -307,6 +309,7 @@ impl VulkanRenderer { } fn initial_barriers(&self, buf: CommandBuffer, fb: &VulkanImage) { + zone!("initial_barriers"); let mut memory = self.memory.borrow_mut(); let memory = &mut *memory; memory.image_barriers.clear(); @@ -355,6 +358,7 @@ impl VulkanRenderer { } fn begin_rendering(&self, buf: CommandBuffer, fb: &VulkanImage, clear: Option<&Color>) { + zone!("begin_rendering"); let rendering_attachment_info = { let mut rai = RenderingAttachmentInfo::default() .image_view(fb.render_view.unwrap_or(fb.texture_view)) @@ -388,6 +392,7 @@ impl VulkanRenderer { } fn set_viewport(&self, buf: CommandBuffer, fb: &VulkanImage) { + zone!("set_viewport"); let viewport = Viewport { x: 0.0, y: 0.0, @@ -419,6 +424,7 @@ impl VulkanRenderer { fb: &VulkanImage, opts: &[GfxApiOpt], ) -> Result<(), VulkanError> { + zone!("record_draws"); let pipelines = self.get_or_create_pipelines(fb.format.vk_format)?; let dev = &self.device.device; let mut current_pipeline = None; @@ -519,12 +525,14 @@ impl VulkanRenderer { } fn end_rendering(&self, buf: CommandBuffer) { + zone!("end_rendering"); unsafe { self.device.device.cmd_end_rendering(buf); } } fn copy_bridge_to_dmabuf(&self, buf: CommandBuffer, fb: &VulkanImage) { + zone!("copy_bridge_to_dmabuf"); let Some(bridge) = &fb.bridge else { return; }; @@ -584,6 +592,7 @@ impl VulkanRenderer { } fn final_barriers(&self, buf: CommandBuffer, fb: &VulkanImage) { + zone!("final_barriers"); let mut memory = self.memory.borrow_mut(); let memory = &mut *memory; memory.image_barriers.clear(); @@ -625,6 +634,7 @@ impl VulkanRenderer { } fn end_command_buffer(&self, buf: CommandBuffer) -> Result<(), VulkanError> { + zone!("end_command_buffer"); unsafe { self.device .device @@ -634,6 +644,7 @@ impl VulkanRenderer { } fn create_wait_semaphores(&self, fb: &VulkanImage) -> Result<(), VulkanError> { + zone!("create_wait_semaphores"); let mut memory = self.memory.borrow_mut(); let memory = &mut *memory; memory.wait_semaphore_infos.clear(); @@ -658,6 +669,7 @@ impl VulkanRenderer { match sync { AcquireSync::None => {} AcquireSync::Implicit { .. } => { + zone!("import implicit"); for plane in &buf.template.dmabuf.planes { let fd = dma_buf_export_sync_file(&plane.fd, flag) .map_err(VulkanError::IoctlExportSyncFile)?; @@ -694,6 +706,7 @@ impl VulkanRenderer { } fn import_release_semaphore(&self, fb: &VulkanImage) { + zone!("import_release_semaphore"); let memory = &mut *self.memory.borrow_mut(); let sync_file = match memory.release_sync_file.as_ref() { Some(sync_file) => sync_file, @@ -727,6 +740,7 @@ impl VulkanRenderer { } fn submit(&self, buf: CommandBuffer) -> Result<(), VulkanError> { + zone!("submit"); let mut memory = self.memory.borrow_mut(); let release_fence = self.device.create_fence()?; let command_buffer_info = CommandBufferSubmitInfo::default().command_buffer(buf); @@ -743,6 +757,7 @@ impl VulkanRenderer { ) .map_err(VulkanError::Submit)?; } + zone!("export_sync_file"); let release_sync_file = match release_fence.export_sync_file() { Ok(s) => Some(s), Err(e) => { @@ -761,6 +776,7 @@ impl VulkanRenderer { } fn create_pending_frame(self: &Rc, buf: Rc) { + zone!("create_pending_frame"); let point = self.allocate_point(); let mut memory = self.memory.borrow_mut(); let frame = Rc::new(PendingFrame { @@ -773,12 +789,15 @@ impl VulkanRenderer { _release_fence: memory.release_fence.take(), }); self.pending_frames.set(frame.point, frame.clone()); - let future = self.eng.spawn(await_release( - memory.release_sync_file.clone(), - self.ring.clone(), - frame.clone(), - self.clone(), - )); + let future = self.eng.spawn( + "await release", + await_release( + memory.release_sync_file.clone(), + self.ring.clone(), + frame.clone(), + self.clone(), + ), + ); frame.waiter.set(Some(future)); } @@ -976,6 +995,7 @@ impl VulkanRenderer { opts: &[GfxApiOpt], clear: Option<&Color>, ) -> Result, VulkanError> { + zone!("execute"); let res = self.try_execute(fb, opts, clear); let sync_file = { let mut memory = self.memory.borrow_mut(); @@ -989,6 +1009,7 @@ impl VulkanRenderer { } pub(super) fn allocate_command_buffer(&self) -> Result, VulkanError> { + zone!("allocate_command_buffer"); let buf = match self.command_buffers.pop() { Some(b) => b, _ => { @@ -1000,6 +1021,7 @@ impl VulkanRenderer { } fn allocate_semaphore(&self) -> Result, VulkanError> { + zone!("allocate_semaphore"); let semaphore = match self.wait_semaphores.pop() { Some(s) => s, _ => self.device.create_semaphore()?, diff --git a/src/gfx_apis/vulkan/semaphore.rs b/src/gfx_apis/vulkan/semaphore.rs index aeee83ec..71cfc9a7 100644 --- a/src/gfx_apis/vulkan/semaphore.rs +++ b/src/gfx_apis/vulkan/semaphore.rs @@ -37,6 +37,7 @@ impl VulkanDevice { impl VulkanSemaphore { pub fn import_sync_file(&self, sync_file: OwnedFd) -> Result<(), VulkanError> { + zone!("import_sync_file"); let fd_info = ImportSemaphoreFdInfoKHR::default() .fd(sync_file.raw()) .flags(SemaphoreImportFlags::TEMPORARY) diff --git a/src/gfx_apis/vulkan/shm_image.rs b/src/gfx_apis/vulkan/shm_image.rs index af050af3..e5dc272e 100644 --- a/src/gfx_apis/vulkan/shm_image.rs +++ b/src/gfx_apis/vulkan/shm_image.rs @@ -164,14 +164,10 @@ impl VulkanShmImage { else { return Ok(()); }; - let future = img.renderer.eng.spawn(await_upload( - point, - img.clone(), - cmd, - sync_file, - fence, - staging, - )); + let future = img.renderer.eng.spawn( + "await upload", + await_upload(point, img.clone(), cmd, sync_file, fence, staging), + ); img.renderer.pending_uploads.set(point, future); Ok(()) } @@ -519,13 +515,10 @@ impl VulkanShmImage { else { return Ok(()); }; - let future = img.renderer.eng.spawn(await_async_upload( - point, - img.clone(), - cmd, - fence, - sync_file, - )); + let future = img.renderer.eng.spawn( + "await async upload", + await_async_upload(point, img.clone(), cmd, fence, sync_file), + ); img.renderer.pending_uploads.set(point, future); Ok(()) } diff --git a/src/ifs/ext_idle_notifier_v1.rs b/src/ifs/ext_idle_notifier_v1.rs index b443ef89..ca70529b 100644 --- a/src/ifs/ext_idle_notifier_v1.rs +++ b/src/ifs/ext_idle_notifier_v1.rs @@ -72,7 +72,11 @@ impl ExtIdleNotifierV1RequestHandler for ExtIdleNotifierV1 { }); track!(self.client, notification); self.client.add_client_obj(¬ification)?; - let future = self.client.state.eng.spawn(run(notification.clone())); + let future = self + .client + .state + .eng + .spawn("idle notifier", run(notification.clone())); notification.task.set(Some(future)); Ok(()) } diff --git a/src/ifs/wl_seat.rs b/src/ifs/wl_seat.rs index 45e7e4b9..b237f3da 100644 --- a/src/ifs/wl_seat.rs +++ b/src/ifs/wl_seat.rs @@ -270,7 +270,7 @@ impl WlSeatGlobal { }); slf.pointer_cursor.set_owner(slf.clone()); let seat = slf.clone(); - let future = state.eng.spawn(async move { + let future = state.eng.spawn("seat handler", async move { loop { seat.tree_changed.triggered().await; seat.state.tree_changed_sent.set(false); diff --git a/src/io_uring/ops/read_write_no_cancel/tests.rs b/src/io_uring/ops/read_write_no_cancel/tests.rs index d334426a..ef50bba0 100644 --- a/src/io_uring/ops/read_write_no_cancel/tests.rs +++ b/src/io_uring/ops/read_write_no_cancel/tests.rs @@ -17,7 +17,7 @@ fn cancel(timeout: bool) { let wheel = Wheel::new(&eng, &ring).unwrap(); let queue = Rc::new(AsyncQueue::new()); let queue2 = queue.clone(); - let _fut1 = eng.spawn(async move { + let _fut1 = eng.spawn("", async move { let (read, _write) = uapi::pipe().unwrap(); let mut buf = [10]; let res = ring @@ -29,7 +29,7 @@ fn cancel(timeout: bool) { )); ring.stop(); }); - let _fut2 = eng.spawn(async move { + let _fut2 = eng.spawn("", async move { let id = queue2.pop().await; if timeout { wheel.timeout(1).await.unwrap(); diff --git a/src/it.rs b/src/it.rs index 1e400c43..3730fd45 100644 --- a/src/it.rs +++ b/src/it.rs @@ -143,7 +143,7 @@ fn run_test(it_run: &ItRun, test: &'static dyn TestCase, cfg: Rc) { let errors = errors2.clone(); Box::new(async move { let future: Pin<_> = test.run(testrun.clone()).into(); - let future = state.eng.spawn2(Phase::Present, future); + let future = state.eng.spawn2("testrun", Phase::Present, future); let timeout = state.wheel.timeout(500000); match future::select(future, timeout).await { Either::Left((Ok(..), _)) => {} diff --git a/src/it/test_backend.rs b/src/it/test_backend.rs index 300387ce..383dab9e 100644 --- a/src/it/test_backend.rs +++ b/src/it/test_backend.rs @@ -271,7 +271,7 @@ where impl Backend for TestBackend { fn run(self: Rc) -> SpawnedFuture>> { let future = (self.test_future)(&self.state); - self.state.eng.spawn(async move { + self.state.eng.spawn("", async move { let future: Pin<_> = future.into(); future.await; Ok(()) diff --git a/src/it/test_transport.rs b/src/it/test_transport.rs index a869f460..5b966546 100644 --- a/src/it/test_transport.rs +++ b/src/it/test_transport.rs @@ -147,6 +147,7 @@ impl TestTransport { pub fn init(self: &Rc) { self.incoming.set(Some( self.run.state.eng.spawn( + "", Incoming { tc: self.clone(), buf: BufFdIn::new(&self.socket, &self.run.state.ring), @@ -156,6 +157,7 @@ impl TestTransport { )); self.outgoing.set(Some( self.run.state.eng.spawn( + "", Outgoing { tc: self.clone(), buf: BufFdOut::new(&self.socket, &self.run.state.ring), diff --git a/src/main.rs b/src/main.rs index 4e47f8dd..a8b41234 100644 --- a/src/main.rs +++ b/src/main.rs @@ -43,6 +43,8 @@ mod macros; #[macro_use] mod leaks; +#[macro_use] +mod tracy; mod acceptor; mod allocator; mod async_engine; diff --git a/src/pipewire/pw_con.rs b/src/pipewire/pw_con.rs index 099d92c6..ea8cdb12 100644 --- a/src/pipewire/pw_con.rs +++ b/src/pipewire/pw_con.rs @@ -347,8 +347,12 @@ impl PwConHolder { data.send_hello(); data.send_properties(); let con = Rc::new(PwConHolder { - outgoing: Cell::new(Some(eng.spawn(data.clone().handle_outgoing()))), - incoming: Cell::new(Some(eng.spawn(data.clone().handle_incoming()))), + outgoing: Cell::new(Some( + eng.spawn("pw outgoing", data.clone().handle_outgoing()), + )), + incoming: Cell::new(Some( + eng.spawn("pw incoming", data.clone().handle_incoming()), + )), con: data, }); con.con.holder.set(Rc::downgrade(&con)); diff --git a/src/pipewire/pw_ifs/pw_client_node.rs b/src/pipewire/pw_ifs/pw_client_node.rs index 53e2b141..e8413e97 100644 --- a/src/pipewire/pw_ifs/pw_client_node.rs +++ b/src/pipewire/pw_ifs/pw_client_node.rs @@ -745,7 +745,9 @@ impl PwClientNode { let typed = map.typed::(); self.activation.set(Some(typed.clone())); self.transport_in.set(Some( - self.con.eng.spawn(self.clone().transport_in(typed, readfd)), + self.con + .eng + .spawn("pw transport in", self.clone().transport_in(typed, readfd)), )); self.transport_out.set(Some(writefd)); Ok(()) diff --git a/src/portal.rs b/src/portal.rs index 574a864c..5f9905b6 100644 --- a/src/portal.rs +++ b/src/portal.rs @@ -76,7 +76,7 @@ pub struct PortalStartup { impl PortalStartup { pub async fn spawn(self, eng: Rc, ring: Rc, logger: Arc) { - let f1 = eng.spawn({ + let f1 = eng.spawn("check portal exit code", { let ring = ring.clone(); async move { if let Err(e) = ring.readable(&self.pidfd).await { @@ -103,7 +103,7 @@ impl PortalStartup { } } }); - let f2 = eng.spawn({ + let f2 = eng.spawn("portal logger", { let ring = ring.clone(); let logger = logger.clone(); async move { @@ -155,7 +155,10 @@ fn run(logger: Arc, freestanding: bool) { fatal!("Could not create an IO-uring: {}", ErrorFmt(e)); } }; - let _f = eng.spawn(run_async(eng.clone(), ring.clone(), logger, freestanding)); + let _f = eng.spawn( + "portal", + run_async(eng.clone(), ring.clone(), logger, freestanding), + ); if let Err(e) = ring.run() { fatal!("The IO-uring returned an error: {}", ErrorFmt(e)); } diff --git a/src/portal/ptr_gui.rs b/src/portal/ptr_gui.rs index 828a7d3f..5f65e332 100644 --- a/src/portal/ptr_gui.rs +++ b/src/portal/ptr_gui.rs @@ -579,11 +579,11 @@ impl WindowData { fractional_scale, seats: Default::default(), }); - data.render_task.set(Some( - dpy.state - .eng - .spawn2(Phase::Present, data.clone().render_task()), - )); + data.render_task.set(Some(dpy.state.eng.spawn2( + "render", + Phase::Present, + data.clone().render_task(), + ))); data.fractional_scale.owner.set(Some(data.clone())); data } diff --git a/src/security_context_acceptor.rs b/src/security_context_acceptor.rs index 7d4ae7d0..538b322f 100644 --- a/src/security_context_acceptor.rs +++ b/src/security_context_acceptor.rs @@ -64,12 +64,16 @@ impl SecurityContextAcceptors { close_future: Cell::new(None), }); log::info!("Creating security acceptor {acceptor}"); - acceptor - .listen_future - .set(Some(state.eng.spawn(acceptor.clone().accept()))); - acceptor - .close_future - .set(Some(state.eng.spawn(acceptor.clone().close()))); + acceptor.listen_future.set(Some( + state + .eng + .spawn("security accept", acceptor.clone().accept()), + )); + acceptor.close_future.set(Some( + state + .eng + .spawn("security await close", acceptor.clone().close()), + )); self.acceptors.set(acceptor.id, acceptor); } } diff --git a/src/sighand.rs b/src/sighand.rs index 3f05b77f..bd403163 100644 --- a/src/sighand.rs +++ b/src/sighand.rs @@ -32,7 +32,7 @@ pub fn install( Ok(fd) => Rc::new(fd), Err(e) => return Err(SighandError::CreateFailed(e.into())), }; - Ok(eng.spawn(handle_signals(fd, ring.clone()))) + Ok(eng.spawn("signal handler", handle_signals(fd, ring.clone()))) } async fn handle_signals(fd: Rc, ring: Rc) { diff --git a/src/state.rs b/src/state.rs index be74949a..fe5f8abf 100644 --- a/src/state.rs +++ b/src/state.rs @@ -729,7 +729,7 @@ impl State { } let mut handler = self.xwayland.handler.borrow_mut(); if handler.is_none() { - *handler = Some(self.eng.spawn(xwayland::manage(self.clone()))); + *handler = Some(self.eng.spawn("xwayland", xwayland::manage(self.clone()))); } } diff --git a/src/tasks/connector.rs b/src/tasks/connector.rs index d305974d..48e74020 100644 --- a/src/tasks/connector.rs +++ b/src/tasks/connector.rs @@ -41,7 +41,7 @@ pub fn handle(state: &Rc, connector: &Rc) { state: state.clone(), data: data.clone(), }; - let future = state.eng.spawn(oh.handle()); + let future = state.eng.spawn("connector handler", oh.handle()); data.handler.set(Some(future)); if state.connectors.set(id, data).is_some() { panic!("Connector id has been reused"); @@ -141,7 +141,10 @@ impl ConnectorHandler { &self.data, &desired_state, )); - let _schedule = self.state.eng.spawn(schedule.clone().drive()); + let _schedule = self + .state + .eng + .spawn("output schedule", schedule.clone().drive()); let on = Rc::new(OutputNode { id: self.state.node_ids.next(), workspaces: Default::default(), diff --git a/src/tasks/drmdev.rs b/src/tasks/drmdev.rs index 5aeed350..b629d632 100644 --- a/src/tasks/drmdev.rs +++ b/src/tasks/drmdev.rs @@ -34,7 +34,7 @@ pub fn handle(state: &Rc, dev: Rc) { state: state.clone(), data: data.clone(), }; - let future = state.eng.spawn(oh.handle()); + let future = state.eng.spawn("drmdev handler", oh.handle()); data.handler.set(Some(future)); if state.drm_devs.set(id, data).is_some() { panic!("Drm device id has been reused"); diff --git a/src/tasks/input_device.rs b/src/tasks/input_device.rs index d255a5c1..2268beb6 100644 --- a/src/tasks/input_device.rs +++ b/src/tasks/input_device.rs @@ -35,7 +35,7 @@ pub fn handle(state: &Rc, dev: Rc) { data: data.clone(), ae: ae.clone(), }; - let handler = state.eng.spawn(oh.handle()); + let handler = state.eng.spawn("input dev handler", oh.handle()); state.input_device_handlers.borrow_mut().insert( dev.id(), InputDeviceData { diff --git a/src/tools/tool_client.rs b/src/tools/tool_client.rs index 048cf3bc..38fdac8f 100644 --- a/src/tools/tool_client.rs +++ b/src/tools/tool_client.rs @@ -122,7 +122,7 @@ where }; let eng2 = eng.clone(); let ring2 = ring.clone(); - let _f = eng.spawn(async move { + let _f = eng.spawn("tool client", async move { let tc = match ToolClient::try_new(logger, eng2, ring2).await { Ok(tc) => tc, Err(e) => handle_error(e), @@ -199,6 +199,7 @@ impl ToolClient { }); slf.incoming.set(Some( slf.eng.spawn( + "tool client incoming", Incoming { tc: slf.clone(), buf: BufFdIn::new(&socket, &slf.ring), @@ -208,6 +209,7 @@ impl ToolClient { )); slf.outgoing.set(Some( slf.eng.spawn( + "tool client outgoing", Outgoing { tc: slf.clone(), buf: BufFdOut::new(&socket, &slf.ring), @@ -239,7 +241,7 @@ impl ToolClient { if let Some(res) = res { let id = slf.next_id.fetch_add(1); let slf2 = slf.clone(); - let future = slf.eng.spawn(async move { + let future = slf.eng.spawn("tool client handler", async move { res.await; slf2.pending_futures.borrow_mut().remove(&id); }); diff --git a/src/tracy.rs b/src/tracy.rs new file mode 100644 index 00000000..fa1e46c4 --- /dev/null +++ b/src/tracy.rs @@ -0,0 +1,15 @@ +#[cfg(feature = "tracy")] +#[macro_use] +mod tracy_impl; + +#[cfg(feature = "tracy")] +use tracy_impl as imp; + +#[cfg(not(feature = "tracy"))] +#[macro_use] +mod tracy_noop; + +#[cfg(not(feature = "tracy"))] +use tracy_noop as imp; + +pub use imp::{enable_profiler, FrameName, ZoneName}; diff --git a/src/tracy/tracy_impl.rs b/src/tracy/tracy_impl.rs new file mode 100644 index 00000000..4828ace7 --- /dev/null +++ b/src/tracy/tracy_impl.rs @@ -0,0 +1,212 @@ +use { + ahash::AHashMap, + parking_lot::Mutex, + std::{ + ffi::{CStr, CString}, + ptr, + sync::{ + atomic::{AtomicBool, Ordering::Relaxed}, + LazyLock, + }, + }, + tracy_client_sys::{ + ___tracy_c_zone_context, ___tracy_emit_frame_mark_end, ___tracy_emit_frame_mark_start, + ___tracy_emit_zone_end, ___tracy_source_location_data, ___tracy_startup_profiler, + }, +}; + +#[derive(Copy, Clone)] +pub struct ZoneName { + data: &'static ZoneNameData, +} + +struct ZoneNameData { + _name: CString, + loc: ___tracy_source_location_data, +} + +unsafe impl Sync for ZoneNameData {} +unsafe impl Send for ZoneNameData {} + +static CACHE: LazyLock>> = LazyLock::new(|| Default::default()); + +impl ZoneName { + pub fn __get(name: &str) -> Self { + let mut cache = CACHE.lock(); + if let Some(span) = cache.get(name) { + return *span; + } + let cname = CString::new(name).unwrap(); + let span = ZoneName { + data: Box::leak(Box::new(ZoneNameData { + loc: ___tracy_source_location_data { + name: cname.as_ptr(), + function: ptr::null(), + file: ptr::null(), + line: 0, + color: 0, + }, + _name: cname, + })), + }; + cache.insert(name.to_string(), span); + span + } + + #[inline(always)] + pub fn __enter(self) -> RunningZone { + if enabled() { + unsafe { + let zone = tracy_client_sys::___tracy_emit_zone_begin(&self.data.loc, 1); + RunningZone(Some(zone)) + } + } else { + RunningZone(None) + } + } +} + +macro_rules! create_zone_name { + ($($tt:tt)*) => { + crate::tracy::ZoneName::__get(&format!($($tt)*)) + }; +} + +pub struct RunningZone(Option<___tracy_c_zone_context>); + +impl Drop for RunningZone { + #[inline(always)] + fn drop(&mut self) { + if let Some(zone) = self.0 { + unsafe { + ___tracy_emit_zone_end(zone); + } + } + } +} + +macro_rules! dynamic_raii_zone { + ($name:expr) => {{ + let name: ZoneName = $name; + name.__enter() + }}; +} + +macro_rules! dynamic_zone { + ($name:expr) => { + let _zone = dynamic_raii_zone!($name); + }; +} + +macro_rules! raii_zone { + ($($tt:tt)*) => { + { + static CACHE: std::sync::LazyLock = std::sync::LazyLock::new(|| { + create_zone_name!($($tt)*) + }); + CACHE.__enter() + } + }; +} + +macro_rules! zone { + ($($tt:tt)*) => { + let _zone = raii_zone!($($tt)*); + }; +} + +#[derive(Copy, Clone)] +pub struct FrameName { + name: &'static CString, +} + +static FRAME_CACHE: LazyLock>> = + LazyLock::new(|| Default::default()); + +impl FrameName { + pub fn get(name: &str) -> Self { + let mut cache = FRAME_CACHE.lock(); + if let Some(frame_name) = cache.get(name) { + return *frame_name; + } + let cname = CString::new(name).unwrap(); + let span = Self { + name: Box::leak(Box::new(cname)), + }; + cache.insert(name.to_string(), span); + span + } + + #[inline(always)] + pub fn __start(self) -> RenderingFrame { + if enabled() { + unsafe { + ___tracy_emit_frame_mark_start(self.name.as_ptr()); + } + } + RenderingFrame { name: self.name } + } +} + +macro_rules! raii_frame { + ($name:expr) => {{ + let name: FrameName = $name; + name.__start() + }}; +} + +macro_rules! frame { + ($name:expr) => { + let _frame = raii_frame!($name); + }; +} + +pub struct RenderingFrame { + name: &'static CString, +} + +impl Drop for RenderingFrame { + #[inline(always)] + fn drop(&mut self) { + if enabled() { + unsafe { + ___tracy_emit_frame_mark_end(self.name.as_ptr()); + } + } + } +} + +#[no_mangle] +#[allow(static_mut_refs)] +unsafe extern "C" fn ___tracy_demangle( + mangled: *const std::ffi::c_char, +) -> *const std::ffi::c_char { + use std::io::Write; + if mangled.is_null() { + return ptr::null(); + } + let Ok(mangled) = CStr::from_ptr(mangled).to_str() else { + return ptr::null(); + }; + let demangled = rustc_demangle::demangle(mangled); + static mut BUF: Vec = Vec::new(); + BUF.clear(); + if let Err(_) = write!(BUF, "{demangled:#}\0") { + return ptr::null(); + } + BUF.as_ptr().cast() +} + +static ENABLED: AtomicBool = AtomicBool::new(false); + +#[inline(always)] +fn enabled() -> bool { + ENABLED.load(Relaxed) +} + +pub fn enable_profiler() { + unsafe { + ___tracy_startup_profiler(); + } + ENABLED.store(true, Relaxed); +} diff --git a/src/tracy/tracy_noop.rs b/src/tracy/tracy_noop.rs new file mode 100644 index 00000000..da88c2b6 --- /dev/null +++ b/src/tracy/tracy_noop.rs @@ -0,0 +1,51 @@ +#![allow(unused_macros)] + +#[derive(Copy, Clone)] +pub struct ZoneName; + +#[derive(Copy, Clone)] +pub struct FrameName; + +impl FrameName { + pub fn get(_name: &str) -> Self { + Self + } +} + +macro_rules! create_zone_name { + ($($tt:tt)*) => { + crate::tracy::ZoneName + }; +} + +macro_rules! dynamic_raii_zone { + ($name:expr) => {}; +} + +macro_rules! dynamic_zone { + ($name:expr) => {}; +} + +macro_rules! raii_zone { + ($($tt:tt)*) => { + () + }; +} + +macro_rules! zone { + ($($tt:tt)*) => {}; +} + +macro_rules! raii_frame { + ($name:expr) => { + () + }; +} + +macro_rules! frame { + ($name:expr) => {}; +} + +pub fn enable_profiler() { + // nothing +} diff --git a/src/utils/run_toplevel.rs b/src/utils/run_toplevel.rs index 16bd0ca4..b0422d32 100644 --- a/src/utils/run_toplevel.rs +++ b/src/utils/run_toplevel.rs @@ -19,7 +19,7 @@ impl RunToplevel { let slf = Rc::new(RunToplevel { queue: Default::default(), }); - let future = eng.spawn({ + let future = eng.spawn("run toplevel", { let slf = slf.clone(); async move { loop { diff --git a/src/video/drm/wait_for_sync_obj.rs b/src/video/drm/wait_for_sync_obj.rs index f22a1095..39f95e6a 100644 --- a/src/video/drm/wait_for_sync_obj.rs +++ b/src/video/drm/wait_for_sync_obj.rs @@ -140,7 +140,7 @@ impl WaitForSyncObj { trigger: Default::default(), }); Waiter { - _task: self.eng.spawn(waiter.clone().run()), + _task: self.eng.spawn("wait for sync obj", waiter.clone().run()), inner: waiter, } } diff --git a/src/wheel.rs b/src/wheel.rs index fdbb2dc3..2001cc01 100644 --- a/src/wheel.rs +++ b/src/wheel.rs @@ -128,7 +128,7 @@ impl Wheel { cached_futures: Default::default(), }); data.dispatcher - .set(Some(eng.spawn(data.clone().dispatch()))); + .set(Some(eng.spawn("wheel", data.clone().dispatch()))); Ok(Rc::new(Wheel { data })) } diff --git a/src/wl_usr.rs b/src/wl_usr.rs index 1fb88500..e7f5321d 100644 --- a/src/wl_usr.rs +++ b/src/wl_usr.rs @@ -146,6 +146,7 @@ impl UsrCon { ); slf.incoming.set(Some( slf.eng.spawn( + "wl_usr incoming", Incoming { con: slf.clone(), buf: BufFdIn::new(&socket, &slf.ring), @@ -156,6 +157,7 @@ impl UsrCon { )); slf.outgoing.set(Some( slf.eng.spawn( + "wl_usr outgoing", Outgoing { con: slf.clone(), buf: BufFdOut::new(&socket, &slf.ring), diff --git a/src/xcon.rs b/src/xcon.rs index 04a0d458..9b1e340f 100644 --- a/src/xcon.rs +++ b/src/xcon.rs @@ -453,9 +453,11 @@ impl Xcon { xorg: CloneCell::new(Weak::new()), events: Default::default(), }); - let outgoing = state - .eng - .spawn2(Phase::PostLayout, handle_outgoing(data.clone())); + let outgoing = state.eng.spawn2( + "xcon send", + Phase::PostLayout, + handle_outgoing(data.clone()), + ); let mut buf = data.bufio.buf(); let mut fds = vec![]; { @@ -502,7 +504,9 @@ impl Xcon { return Err(XconError::Authenticate(reason.to_owned())); } let setup = Setup::deserialize(&mut parser)?; - let incoming = state.eng.spawn(handle_incoming(data.clone(), incoming)); + let incoming = state + .eng + .spawn("X incoming", handle_incoming(data.clone(), incoming)); let slf = Rc::new(Self { extensions: data.fetch_extension_data().await?, outgoing: Cell::new(Some(outgoing)), diff --git a/src/xwayland.rs b/src/xwayland.rs index 1bbd8d13..db27efa3 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -150,7 +150,9 @@ async fn run( Ok(w) => w, Err(e) => return Err(XWaylandError::Socketpair(e.into())), }; - let stderr_read = state.eng.spawn(log_xwayland(state.clone(), stderr_read)); + let stderr_read = state + .eng + .spawn("log Xwayland", log_xwayland(state.clone(), stderr_read)); let pidfd = forker .xwayland( &state, @@ -188,7 +190,7 @@ async fn run( Ok(w) => w, Err(e) => return Err(XWaylandError::CreateWm(Box::new(e))), }; - let _wm = state.eng.spawn(wm.run()); + let _wm = state.eng.spawn("XWM", wm.run()); state.ring.readable(&pidfd).await?; } state.xwayland.queue.clear(); diff --git a/src/xwayland/xwm.rs b/src/xwayland/xwm.rs index 39335c7c..1e635c4d 100644 --- a/src/xwayland/xwm.rs +++ b/src/xwayland/xwm.rs @@ -1678,7 +1678,7 @@ impl Wm { }; self.shared .transfers - .set(id, self.state.eng.spawn(wtx.run())); + .set(id, self.state.eng.spawn("wayland to X transfer", wtx.run())); } } } @@ -1781,9 +1781,12 @@ impl Wm { state: self.state.clone(), shared: self.shared.clone(), }; - self.shared - .transfers - .set(id, self.state.eng.spawn(transfer.run())); + self.shared.transfers.set( + id, + self.state + .eng + .spawn("X to wayland transfer", transfer.run()), + ); } }