1
0
Fork 0
forked from wry/wry

all: use tracy for tracing

This commit is contained in:
Julian Orth 2024-09-15 18:08:54 +02:00
parent 50186e764e
commit ccad3cf0fb
56 changed files with 647 additions and 171 deletions

View file

@ -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))

View file

@ -64,16 +64,21 @@ impl AsyncEngine {
}
}
pub fn spawn<T, F: Future<Output = T> + 'static>(self: &Rc<Self>, f: F) -> SpawnedFuture<T> {
self.spawn_(Phase::EventHandling, f)
pub fn spawn<T, F: Future<Output = T> + 'static>(
self: &Rc<Self>,
name: &str,
f: F,
) -> SpawnedFuture<T> {
self.spawn_(name, Phase::EventHandling, f)
}
pub fn spawn2<T, F: Future<Output = T> + 'static>(
self: &Rc<Self>,
name: &str,
phase: Phase,
f: F,
) -> SpawnedFuture<T> {
self.spawn_(phase, f)
self.spawn_(name, phase, f)
}
pub fn yield_now(self: &Rc<Self>) -> Yield {

View file

@ -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<T, F: Future<Output = T>> {
data: UnsafeCell<TaskData<T, F>>,
waker: Cell<Option<Waker>>,
queue: Rc<AsyncEngine>,
#[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_<T, F: Future<Output = T>>(
self: &Rc<Self>,
#[cfg_attr(not(feature = "tracy"), expect(unused_variables))] name: &str,
phase: Phase,
f: F,
) -> SpawnedFuture<T> {
@ -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<T, F: Future<Output = T>> Task<T, F> {
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);

View file

@ -163,8 +163,14 @@ impl Debug for MetalBackend {
impl MetalBackend {
async fn run(self: Rc<Self>) -> 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<Self>) -> SpawnedFuture<Result<(), Box<dyn Error>>> {
let slf = self.clone();
self.state.eng.spawn(async move {
self.state.eng.spawn("metal backend", async move {
slf.run().await?;
Ok(())
})

View file

@ -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<Self>) {
#[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 {

View file

@ -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)

View file

@ -249,7 +249,7 @@ pub async fn create(state: &Rc<State>) -> Result<Rc<XBackend>, XBackendError> {
impl Backend for XBackend {
fn run(self: Rc<Self>) -> SpawnedFuture<Result<(), Box<dyn Error>>> {
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<Self>) -> 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

View file

@ -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!(

View file

@ -14,9 +14,16 @@ use {
};
pub async fn client(data: Rc<Client>) {
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 => { },

View file

@ -255,6 +255,7 @@ impl CpuJob for CloseMemWork {
impl CpuWork for CloseMemWork {
fn run(&mut self) -> Option<Box<dyn AsyncCpuWork>> {
zone!("CloseMemWork");
self.fd.take();
unsafe {
c::munmap(self.data as _, self.data.len());

View file

@ -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()),
),
]
}

View file

@ -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();

View file

@ -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));
}

View file

@ -35,6 +35,7 @@ impl ImgCopyWork {
impl CpuWork for ImgCopyWork {
fn run(&mut self) -> Option<Box<dyn AsyncCpuWork>> {
zone!("ImgCopyWork");
for rect in &self.rects {
let mut offset = rect.y1() * self.stride + rect.x1() * self.bpp;
if rect.width() == self.width {

View file

@ -102,7 +102,7 @@ impl AsyncCpuWork for ReadWriteWorkConfig {
completion: WorkCompletion,
) -> SpawnedFuture<CompletedWork> {
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);

View file

@ -62,7 +62,7 @@ impl AsyncCpuWork for AsyncWork {
completion: WorkCompletion,
) -> SpawnedFuture<CompletedWork> {
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();
});

View file

@ -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();
}

View file

@ -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)
}

View file

@ -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))
}

View file

@ -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!(

View file

@ -16,9 +16,16 @@ use {
};
pub async fn ei_client(data: Rc<EiClient>) {
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 => { },

View file

@ -109,13 +109,20 @@ impl ForkerProxy {
pub fn install(self: &Rc<Self>, state: &Rc<State>) {
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!(

View file

@ -251,6 +251,7 @@ struct AllocWork {
impl CpuWork for AllocWork {
fn run(&mut self) -> Option<Box<dyn AsyncCpuWork>> {
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<Box<dyn AsyncCpuWork>> {
zone!("FreeWork");
let ua = self.allocation.take().unwrap();
unsafe {
do_free(&mut self.allocator.lock(), &self.device, ua.block, ua.ptr);

View file

@ -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<Self>, buf: Rc<VulkanCommandBuffer>) {
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<Option<SyncFile>, 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<Rc<VulkanCommandBuffer>, 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<Rc<VulkanSemaphore>, VulkanError> {
zone!("allocate_semaphore");
let semaphore = match self.wait_semaphores.pop() {
Some(s) => s,
_ => self.device.create_semaphore()?,

View file

@ -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)

View file

@ -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(())
}

View file

@ -72,7 +72,11 @@ impl ExtIdleNotifierV1RequestHandler for ExtIdleNotifierV1 {
});
track!(self.client, notification);
self.client.add_client_obj(&notification)?;
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(())
}

View file

@ -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);

View file

@ -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();

View file

@ -143,7 +143,7 @@ fn run_test(it_run: &ItRun, test: &'static dyn TestCase, cfg: Rc<TestConfig>) {
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(..), _)) => {}

View file

@ -271,7 +271,7 @@ where
impl Backend for TestBackend {
fn run(self: Rc<Self>) -> SpawnedFuture<Result<(), Box<dyn std::error::Error>>> {
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(())

View file

@ -147,6 +147,7 @@ impl TestTransport {
pub fn init(self: &Rc<Self>) {
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),

View file

@ -43,6 +43,8 @@
mod macros;
#[macro_use]
mod leaks;
#[macro_use]
mod tracy;
mod acceptor;
mod allocator;
mod async_engine;

View file

@ -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));

View file

@ -745,7 +745,9 @@ impl PwClientNode {
let typed = map.typed::<pw_node_activation>();
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(())

View file

@ -76,7 +76,7 @@ pub struct PortalStartup {
impl PortalStartup {
pub async fn spawn(self, eng: Rc<AsyncEngine>, ring: Rc<IoUring>, logger: Arc<Logger>) {
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<Logger>, 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));
}

View file

@ -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
}

View file

@ -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);
}
}

View file

@ -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<OwnedFd>, ring: Rc<IoUring>) {

View file

@ -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())));
}
}

View file

@ -41,7 +41,7 @@ pub fn handle(state: &Rc<State>, connector: &Rc<dyn Connector>) {
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(),

View file

@ -34,7 +34,7 @@ pub fn handle(state: &Rc<State>, dev: Rc<dyn BackendDrmDevice>) {
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");

View file

@ -35,7 +35,7 @@ pub fn handle(state: &Rc<State>, dev: Rc<dyn InputDevice>) {
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 {

View file

@ -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);
});

15
src/tracy.rs Normal file
View file

@ -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};

212
src/tracy/tracy_impl.rs Normal file
View file

@ -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<Mutex<AHashMap<String, ZoneName>>> = 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<crate::tracy::ZoneName> = 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<Mutex<AHashMap<String, FrameName>>> =
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<u8> = 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);
}

51
src/tracy/tracy_noop.rs Normal file
View file

@ -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
}

View file

@ -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 {

View file

@ -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,
}
}

View file

@ -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 }))
}

View file

@ -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),

View file

@ -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)),

View file

@ -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();

View file

@ -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()),
);
}
}