Detailed changes
@@ -80,6 +80,7 @@ use workspace::{
dock::{DockPosition, Panel, PanelEvent},
notifications::{DetachAndPromptErr, ErrorMessagePrompt, NotificationId, NotifyResultExt},
};
+use ztracing::instrument;
actions!(
git_panel,
[
@@ -1197,6 +1198,7 @@ impl GitPanel {
self.selected_entry.and_then(|i| self.entries.get(i))
}
+ #[instrument(skip_all)]
fn open_diff(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
maybe!({
let entry = self.entries.get(self.selected_entry?)?.status_entry()?;
@@ -1247,6 +1249,7 @@ impl GitPanel {
});
}
+ #[instrument(skip_all)]
fn open_file(
&mut self,
_: &menu::SecondaryConfirm,
@@ -5082,9 +5085,9 @@ impl GitPanel {
this.selected_entry = Some(ix);
cx.notify();
if event.modifiers().secondary() {
- this.open_file(&Default::default(), window, cx)
+ this.open_file(&Default::default(), window, cx) // here?
} else {
- this.open_diff(&Default::default(), window, cx);
+ this.open_diff(&Default::default(), window, cx); // here?
this.focus_handle.focus(window, cx);
}
})
@@ -1,9 +1,10 @@
-use crate::{App, PlatformDispatcher, RunnableMeta, RunnableVariant, TaskTiming, profiler};
+use crate::{App, GpuiRunnable, PlatformDispatcher, RunnableMeta, TaskTiming, profiler};
use async_task::Runnable;
use futures::channel::mpsc;
use parking_lot::{Condvar, Mutex};
use smol::prelude::*;
use std::{
+ cell::Cell,
fmt::Debug,
marker::PhantomData,
mem::{self, ManuallyDrop},
@@ -81,7 +82,21 @@ pub enum Priority {
Low,
}
+thread_local! {
+static CURRENT_TASKS_PRIORITY: Cell<Priority> = const { Cell::new(Priority::Medium) }; }
+
impl Priority {
+ /// Sets the priority any spawn call from the runnable about
+ /// to be run will use
+ pub(crate) fn set_as_default_for_spawns(&self) {
+ CURRENT_TASKS_PRIORITY.set(*self);
+ }
+
+ /// Returns the priority from the currently running task
+ pub fn inherit() -> Self {
+ CURRENT_TASKS_PRIORITY.get()
+ }
+
#[allow(dead_code)]
pub(crate) const fn probability(&self) -> u32 {
match self {
@@ -329,19 +344,14 @@ impl BackgroundExecutor {
.metadata(RunnableMeta {
location,
app: None,
+ priority: Priority::inherit(),
})
.spawn_unchecked(
move |_| async {
let _notify_guard = NotifyOnDrop(pair);
future.await
},
- move |runnable| {
- dispatcher.dispatch(
- RunnableVariant::Meta(runnable),
- None,
- Priority::default(),
- )
- },
+ move |runnable| dispatcher.dispatch(GpuiRunnable::GpuiSpawned(runnable), None),
)
};
runnable.schedule();
@@ -387,6 +397,7 @@ impl BackgroundExecutor {
};
profiler::add_task_timing(timing);
+ Priority::Realtime(realtime).set_as_default_for_spawns();
runnable.run();
let end = Instant::now();
@@ -399,6 +410,7 @@ impl BackgroundExecutor {
async_task::Builder::new()
.metadata(RunnableMeta {
location,
+ priority,
app: None,
})
.spawn(
@@ -412,13 +424,12 @@ impl BackgroundExecutor {
async_task::Builder::new()
.metadata(RunnableMeta {
location,
+ priority,
app: None,
})
.spawn(
move |_| future,
- move |runnable| {
- dispatcher.dispatch(RunnableVariant::Meta(runnable), label, priority)
- },
+ move |runnable| dispatcher.dispatch(GpuiRunnable::GpuiSpawned(runnable), label),
)
};
@@ -674,11 +685,14 @@ impl BackgroundExecutor {
let (runnable, task) = async_task::Builder::new()
.metadata(RunnableMeta {
location,
+ priority: Priority::inherit(),
app: None,
})
.spawn(move |_| async move {}, {
let dispatcher = self.dispatcher.clone();
- move |runnable| dispatcher.dispatch_after(duration, RunnableVariant::Meta(runnable))
+ move |runnable| {
+ dispatcher.dispatch_after(duration, GpuiRunnable::GpuiSpawned(runnable))
+ }
});
runnable.schedule();
Task(TaskState::Spawned(task))
@@ -785,7 +799,10 @@ impl ForegroundExecutor {
}
}
- /// Enqueues the given Task to run on the main thread at some point in the future.
+ /// Enqueues the given Task to run on the main thread at some point in the
+ /// future. This inherits the priority of the caller. Use
+ /// [`spawn_with_priority`](Self::spawn_with_priority) if you want to
+ /// overwrite that.
#[track_caller]
pub fn spawn<R>(&self, future: impl Future<Output = R> + 'static) -> Task<R>
where
@@ -831,10 +848,11 @@ impl ForegroundExecutor {
let (runnable, task) = spawn_local_with_source_location(
future,
move |runnable| {
- dispatcher.dispatch_on_main_thread(RunnableVariant::Meta(runnable), priority)
+ dispatcher.dispatch_on_main_thread(GpuiRunnable::GpuiSpawned(runnable))
},
RunnableMeta {
location,
+ priority,
app: Some(app),
},
);
@@ -590,7 +590,8 @@ pub(crate) trait PlatformWindow: HasWindowHandle + HasDisplayHandle {
/// be considered part of our public API.
#[doc(hidden)]
pub struct RunnableMeta {
- /// Location of the runnable
+ pub priority: Priority,
+ /// Location of the runnable, only set for futures we spawn
pub location: &'static core::panic::Location<'static>,
/// Weak reference to check if the app is still alive before running this task
pub app: Option<std::sync::Weak<()>>,
@@ -599,6 +600,7 @@ pub struct RunnableMeta {
impl std::fmt::Debug for RunnableMeta {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("RunnableMeta")
+ .field("priority", &self.priority)
.field("location", &self.location)
.field("app_alive", &self.is_app_alive())
.finish()
@@ -615,10 +617,69 @@ impl RunnableMeta {
}
}
+/// Both of these need meta for priority
#[doc(hidden)]
-pub enum RunnableVariant {
- Meta(Runnable<RunnableMeta>),
- Compat(Runnable),
+pub enum GpuiRunnable {
+ /// Spawned by us, we set useful metadata for profiling and scheduling.
+ /// Yay we have nice things!
+ GpuiSpawned(Runnable<RunnableMeta>),
+ /// Spawned by a dependency through runtimelib. We only have the
+ /// runnable ('task'). No access to metadata.
+ DependencySpawned(Runnable<()>),
+}
+
+impl GpuiRunnable {
+ fn run_and_profile(self) -> Instant {
+ if self.app_dropped() {
+ // optimizer will cut it out if it doesnt it does not really matter
+ // cause we are closing the app anyway.
+ return Instant::now();
+ }
+
+ let mut timing = TaskTiming {
+ // use a placeholder location if we dont have one
+ location: self.location().unwrap_or(core::panic::Location::caller()),
+ start: Instant::now(),
+ end: None,
+ };
+
+ crate::profiler::add_task_timing(timing);
+ self.run_unprofiled(); // surrounded by profiling so its ok
+ timing.end = Some(Instant::now());
+ crate::profiler::add_task_timing(timing);
+ timing.start
+ }
+
+ fn app_dropped(&self) -> bool {
+ match self {
+ GpuiRunnable::GpuiSpawned(runnable) => !runnable.metadata().is_app_alive(),
+ GpuiRunnable::DependencySpawned(_) => false,
+ }
+ }
+
+ fn location(&self) -> Option<&'static core::panic::Location<'static>> {
+ match self {
+ GpuiRunnable::GpuiSpawned(runnable) => runnable.metadata().location.into(),
+ GpuiRunnable::DependencySpawned(_) => None,
+ }
+ }
+
+ /// ONLY use for tests or headless client.
+ /// ideally everything should be profiled
+ fn run_unprofiled(self) {
+ self.priority().set_as_default_for_spawns();
+ match self {
+ GpuiRunnable::GpuiSpawned(r) => r.run(),
+ GpuiRunnable::DependencySpawned(r) => r.run(),
+ };
+ }
+
+ fn priority(&self) -> Priority {
+ match self {
+ GpuiRunnable::GpuiSpawned(r) => r.metadata().priority,
+ GpuiRunnable::DependencySpawned(_) => Priority::Medium,
+ }
+ }
}
/// This type is public so that our test macro can generate and use it, but it should not
@@ -628,9 +689,9 @@ pub trait PlatformDispatcher: Send + Sync {
fn get_all_timings(&self) -> Vec<ThreadTaskTimings>;
fn get_current_thread_timings(&self) -> Vec<TaskTiming>;
fn is_main_thread(&self) -> bool;
- fn dispatch(&self, runnable: RunnableVariant, label: Option<TaskLabel>, priority: Priority);
- fn dispatch_on_main_thread(&self, runnable: RunnableVariant, priority: Priority);
- fn dispatch_after(&self, duration: Duration, runnable: RunnableVariant);
+ fn dispatch(&self, runnable: GpuiRunnable, label: Option<TaskLabel>);
+ fn dispatch_on_main_thread(&self, runnable: GpuiRunnable);
+ fn dispatch_after(&self, duration: Duration, runnable: GpuiRunnable);
fn spawn_realtime(&self, priority: RealtimePriority, f: Box<dyn FnOnce() + Send>);
fn now(&self) -> Instant {
@@ -5,27 +5,22 @@ use calloop::{
};
use util::ResultExt;
-use std::{
- mem::MaybeUninit,
- thread,
- time::{Duration, Instant},
-};
+use std::{mem::MaybeUninit, thread, time::Duration};
use crate::{
- GLOBAL_THREAD_TIMINGS, PlatformDispatcher, Priority, PriorityQueueReceiver,
- PriorityQueueSender, RealtimePriority, RunnableVariant, THREAD_TIMINGS, TaskLabel, TaskTiming,
- ThreadTaskTimings, profiler,
+ GLOBAL_THREAD_TIMINGS, GpuiRunnable, PlatformDispatcher, Priority, PriorityQueueReceiver,
+ PriorityQueueSender, RealtimePriority, THREAD_TIMINGS, TaskLabel, ThreadTaskTimings,
};
struct TimerAfter {
duration: Duration,
- runnable: RunnableVariant,
+ runnable: GpuiRunnable,
}
pub(crate) struct LinuxDispatcher {
- main_sender: PriorityQueueCalloopSender<RunnableVariant>,
+ main_sender: PriorityQueueCalloopSender<GpuiRunnable>,
timer_sender: Sender<TimerAfter>,
- background_sender: PriorityQueueSender<RunnableVariant>,
+ background_sender: PriorityQueueSender<GpuiRunnable>,
_background_threads: Vec<thread::JoinHandle<()>>,
main_thread_id: thread::ThreadId,
}
@@ -33,7 +28,7 @@ pub(crate) struct LinuxDispatcher {
const MIN_THREADS: usize = 2;
impl LinuxDispatcher {
- pub fn new(main_sender: PriorityQueueCalloopSender<RunnableVariant>) -> Self {
+ pub fn new(main_sender: PriorityQueueCalloopSender<GpuiRunnable>) -> Self {
let (background_sender, background_receiver) = PriorityQueueReceiver::new();
let thread_count =
std::thread::available_parallelism().map_or(MIN_THREADS, |i| i.get().max(MIN_THREADS));
@@ -42,48 +37,16 @@ impl LinuxDispatcher {
// executor
let mut background_threads = (0..thread_count)
.map(|i| {
- let mut receiver = background_receiver.clone();
+ let mut receiver: PriorityQueueReceiver<GpuiRunnable> = background_receiver.clone();
std::thread::Builder::new()
.name(format!("Worker-{i}"))
.spawn(move || {
for runnable in receiver.iter() {
- let start = Instant::now();
-
- let mut location = match runnable {
- RunnableVariant::Meta(runnable) => {
- let location = runnable.metadata().location;
- let timing = TaskTiming {
- location,
- start,
- end: None,
- };
- profiler::add_task_timing(timing);
-
- runnable.run();
- timing
- }
- RunnableVariant::Compat(runnable) => {
- let location = core::panic::Location::caller();
- let timing = TaskTiming {
- location,
- start,
- end: None,
- };
- profiler::add_task_timing(timing);
-
- runnable.run();
- timing
- }
- };
-
- let end = Instant::now();
- location.end = Some(end);
- profiler::add_task_timing(location);
-
+ let started = runnable.run_and_profile();
log::trace!(
"background thread {}: ran runnable. took: {:?}",
i,
- start.elapsed()
+ started.elapsed()
);
}
})
@@ -110,36 +73,7 @@ impl LinuxDispatcher {
calloop::timer::Timer::from_duration(timer.duration),
move |_, _, _| {
if let Some(runnable) = runnable.take() {
- let start = Instant::now();
- let mut timing = match runnable {
- RunnableVariant::Meta(runnable) => {
- let location = runnable.metadata().location;
- let timing = TaskTiming {
- location,
- start,
- end: None,
- };
- profiler::add_task_timing(timing);
-
- runnable.run();
- timing
- }
- RunnableVariant::Compat(runnable) => {
- let timing = TaskTiming {
- location: core::panic::Location::caller(),
- start,
- end: None,
- };
- profiler::add_task_timing(timing);
-
- runnable.run();
- timing
- }
- };
- let end = Instant::now();
-
- timing.end = Some(end);
- profiler::add_task_timing(timing);
+ runnable.run_and_profile();
}
TimeoutAction::Drop
},
@@ -189,15 +123,15 @@ impl PlatformDispatcher for LinuxDispatcher {
thread::current().id() == self.main_thread_id
}
- fn dispatch(&self, runnable: RunnableVariant, _: Option<TaskLabel>, priority: Priority) {
+ fn dispatch(&self, runnable: GpuiRunnable, _: Option<TaskLabel>) {
self.background_sender
- .send(priority, runnable)
+ .send(runnable.priority(), runnable)
.unwrap_or_else(|_| panic!("blocking sender returned without value"));
}
- fn dispatch_on_main_thread(&self, runnable: RunnableVariant, priority: Priority) {
+ fn dispatch_on_main_thread(&self, runnable: GpuiRunnable) {
self.main_sender
- .send(priority, runnable)
+ .send(runnable.priority(), runnable)
.unwrap_or_else(|runnable| {
// NOTE: Runnable may wrap a Future that is !Send.
//
@@ -211,7 +145,7 @@ impl PlatformDispatcher for LinuxDispatcher {
});
}
- fn dispatch_after(&self, duration: Duration, runnable: RunnableVariant) {
+ fn dispatch_after(&self, duration: Duration, runnable: GpuiRunnable) {
self.timer_sender
.send(TimerAfter { duration, runnable })
.ok();
@@ -31,10 +31,7 @@ impl HeadlessClient {
handle
.insert_source(main_receiver, |event, _, _: &mut HeadlessClient| {
if let calloop::channel::Event::Msg(runnable) = event {
- match runnable {
- crate::RunnableVariant::Meta(runnable) => runnable.run(),
- crate::RunnableVariant::Compat(runnable) => runnable.run(),
- };
+ runnable.run_unprofiled();
}
})
.ok();
@@ -23,10 +23,10 @@ use xkbcommon::xkb::{self, Keycode, Keysym, State};
use crate::{
Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId,
- ForegroundExecutor, Keymap, LinuxDispatcher, Menu, MenuItem, OwnedMenu, PathPromptOptions,
- Pixels, Platform, PlatformDisplay, PlatformKeyboardLayout, PlatformKeyboardMapper,
- PlatformTextSystem, PlatformWindow, Point, PriorityQueueCalloopReceiver, Result,
- RunnableVariant, Task, WindowAppearance, WindowParams, px,
+ ForegroundExecutor, GpuiRunnable, Keymap, LinuxDispatcher, Menu, MenuItem, OwnedMenu,
+ PathPromptOptions, Pixels, Platform, PlatformDisplay, PlatformKeyboardLayout,
+ PlatformKeyboardMapper, PlatformTextSystem, PlatformWindow, Point,
+ PriorityQueueCalloopReceiver, Result, Task, WindowAppearance, WindowParams, px,
};
#[cfg(any(feature = "wayland", feature = "x11"))]
@@ -152,7 +152,7 @@ impl LinuxCommon {
pub fn new(
signal: LoopSignal,
liveness: std::sync::Weak<()>,
- ) -> (Self, PriorityQueueCalloopReceiver<RunnableVariant>) {
+ ) -> (Self, PriorityQueueCalloopReceiver<GpuiRunnable>) {
let (main_sender, main_receiver) = PriorityQueueCalloopReceiver::new();
#[cfg(any(feature = "wayland", feature = "x11"))]
@@ -73,17 +73,14 @@ use super::{
window::{ImeInput, WaylandWindowStatePtr},
};
+use crate::platform::{PlatformWindow, blade::BladeContext};
use crate::{
AnyWindowHandle, Bounds, Capslock, CursorStyle, DOUBLE_CLICK_INTERVAL, DevicePixels, DisplayId,
FileDropEvent, ForegroundExecutor, KeyDownEvent, KeyUpEvent, Keystroke, LinuxCommon,
LinuxKeyboardLayout, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent,
MouseExitEvent, MouseMoveEvent, MouseUpEvent, NavigationDirection, Pixels, PlatformDisplay,
PlatformInput, PlatformKeyboardLayout, Point, ResultExt as _, SCROLL_LINES, ScrollDelta,
- ScrollWheelEvent, Size, TouchPhase, WindowParams, point, profiler, px, size,
-};
-use crate::{
- RunnableVariant, TaskTiming,
- platform::{PlatformWindow, blade::BladeContext},
+ ScrollWheelEvent, Size, TouchPhase, WindowParams, point, px, size,
};
use crate::{
SharedString,
@@ -498,38 +495,8 @@ impl WaylandClient {
let handle = handle.clone();
move |event, _, _: &mut WaylandClientStatePtr| {
if let calloop::channel::Event::Msg(runnable) = event {
- handle.insert_idle(|_| {
- let start = Instant::now();
- let mut timing = match runnable {
- RunnableVariant::Meta(runnable) => {
- let location = runnable.metadata().location;
- let timing = TaskTiming {
- location,
- start,
- end: None,
- };
- profiler::add_task_timing(timing);
-
- runnable.run();
- timing
- }
- RunnableVariant::Compat(runnable) => {
- let location = core::panic::Location::caller();
- let timing = TaskTiming {
- location,
- start,
- end: None,
- };
- profiler::add_task_timing(timing);
-
- runnable.run();
- timing
- }
- };
-
- let end = Instant::now();
- timing.end = Some(end);
- profiler::add_task_timing(timing);
+ handle.insert_idle(move |_| {
+ runnable.run_and_profile();
});
}
}
@@ -1,4 +1,4 @@
-use crate::{Capslock, ResultExt as _, RunnableVariant, TaskTiming, profiler, xcb_flush};
+use crate::{Capslock, ResultExt as _, xcb_flush};
use anyhow::{Context as _, anyhow};
use ashpd::WindowIdentifier;
use calloop::{
@@ -313,37 +313,7 @@ impl X11Client {
// events have higher priority and runnables are only worked off after the event
// callbacks.
handle.insert_idle(|_| {
- let start = Instant::now();
- let mut timing = match runnable {
- RunnableVariant::Meta(runnable) => {
- let location = runnable.metadata().location;
- let timing = TaskTiming {
- location,
- start,
- end: None,
- };
- profiler::add_task_timing(timing);
-
- runnable.run();
- timing
- }
- RunnableVariant::Compat(runnable) => {
- let location = core::panic::Location::caller();
- let timing = TaskTiming {
- location,
- start,
- end: None,
- };
- profiler::add_task_timing(timing);
-
- runnable.run();
- timing
- }
- };
-
- let end = Instant::now();
- timing.end = Some(end);
- profiler::add_task_timing(timing);
+ runnable.run_and_profile();
});
}
}
@@ -3,8 +3,8 @@
#![allow(non_snake_case)]
use crate::{
- GLOBAL_THREAD_TIMINGS, PlatformDispatcher, Priority, RealtimePriority, RunnableMeta,
- RunnableVariant, THREAD_TIMINGS, TaskLabel, TaskTiming, ThreadTaskTimings,
+ GLOBAL_THREAD_TIMINGS, GpuiRunnable, PlatformDispatcher, Priority, RealtimePriority,
+ RunnableMeta, THREAD_TIMINGS, TaskLabel, TaskTiming, ThreadTaskTimings,
};
use anyhow::Context;
@@ -28,7 +28,7 @@ use std::{
ffi::c_void,
mem::MaybeUninit,
ptr::{NonNull, addr_of},
- time::{Duration, Instant},
+ time::Duration,
};
use util::ResultExt;
@@ -69,25 +69,25 @@ impl PlatformDispatcher for MacDispatcher {
is_main_thread == YES
}
- fn dispatch(&self, runnable: RunnableVariant, _: Option<TaskLabel>, priority: Priority) {
+ fn dispatch(&self, runnable: GpuiRunnable, _: Option<TaskLabel>) {
+ let queue_priority = match runnable.priority() {
+ Priority::Realtime(_) => unreachable!(),
+ Priority::High => DISPATCH_QUEUE_PRIORITY_HIGH as isize,
+ Priority::Medium => DISPATCH_QUEUE_PRIORITY_DEFAULT as isize,
+ Priority::Low => DISPATCH_QUEUE_PRIORITY_LOW as isize,
+ };
+
let (context, trampoline) = match runnable {
- RunnableVariant::Meta(runnable) => (
+ GpuiRunnable::GpuiSpawned(runnable) => (
runnable.into_raw().as_ptr() as *mut c_void,
Some(trampoline as unsafe extern "C" fn(*mut c_void)),
),
- RunnableVariant::Compat(runnable) => (
+ GpuiRunnable::DependencySpawned(runnable) => (
runnable.into_raw().as_ptr() as *mut c_void,
Some(trampoline_compat as unsafe extern "C" fn(*mut c_void)),
),
};
- let queue_priority = match priority {
- Priority::Realtime(_) => unreachable!(),
- Priority::High => DISPATCH_QUEUE_PRIORITY_HIGH as isize,
- Priority::Medium => DISPATCH_QUEUE_PRIORITY_DEFAULT as isize,
- Priority::Low => DISPATCH_QUEUE_PRIORITY_LOW as isize,
- };
-
unsafe {
dispatch_async_f(
dispatch_get_global_queue(queue_priority, 0),
@@ -97,13 +97,13 @@ impl PlatformDispatcher for MacDispatcher {
}
}
- fn dispatch_on_main_thread(&self, runnable: RunnableVariant, _priority: Priority) {
+ fn dispatch_on_main_thread(&self, runnable: GpuiRunnable) {
let (context, trampoline) = match runnable {
- RunnableVariant::Meta(runnable) => (
+ GpuiRunnable::GpuiSpawned(runnable) => (
runnable.into_raw().as_ptr() as *mut c_void,
Some(trampoline as unsafe extern "C" fn(*mut c_void)),
),
- RunnableVariant::Compat(runnable) => (
+ GpuiRunnable::DependencySpawned(runnable) => (
runnable.into_raw().as_ptr() as *mut c_void,
Some(trampoline_compat as unsafe extern "C" fn(*mut c_void)),
),
@@ -113,13 +113,13 @@ impl PlatformDispatcher for MacDispatcher {
}
}
- fn dispatch_after(&self, duration: Duration, runnable: RunnableVariant) {
+ fn dispatch_after(&self, duration: Duration, runnable: GpuiRunnable) {
let (context, trampoline) = match runnable {
- RunnableVariant::Meta(runnable) => (
+ GpuiRunnable::GpuiSpawned(runnable) => (
runnable.into_raw().as_ptr() as *mut c_void,
Some(trampoline as unsafe extern "C" fn(*mut c_void)),
),
- RunnableVariant::Compat(runnable) => (
+ GpuiRunnable::DependencySpawned(runnable) => (
runnable.into_raw().as_ptr() as *mut c_void,
Some(trampoline_compat as unsafe extern "C" fn(*mut c_void)),
),
@@ -247,82 +247,19 @@ fn set_audio_thread_priority() -> anyhow::Result<()> {
Ok(())
}
+// Note we can not send through a GpuiRunnable as that would require allocating
+// to keep the pointer alive. So we recreate it here.
extern "C" fn trampoline(runnable: *mut c_void) {
let task =
unsafe { Runnable::<RunnableMeta>::from_raw(NonNull::new_unchecked(runnable as *mut ())) };
-
- let metadata = task.metadata();
- let location = metadata.location;
-
- if !metadata.is_app_alive() {
- drop(task);
- return;
- }
-
- let start = Instant::now();
- let timing = TaskTiming {
- location,
- start,
- end: None,
- };
-
- THREAD_TIMINGS.with(|timings| {
- let mut timings = timings.lock();
- let timings = &mut timings.timings;
- if let Some(last_timing) = timings.iter_mut().rev().next() {
- if last_timing.location == timing.location {
- return;
- }
- }
-
- timings.push_back(timing);
- });
-
- task.run();
- let end = Instant::now();
-
- THREAD_TIMINGS.with(|timings| {
- let mut timings = timings.lock();
- let timings = &mut timings.timings;
- let Some(last_timing) = timings.iter_mut().rev().next() else {
- return;
- };
- last_timing.end = Some(end);
- });
+ let task = GpuiRunnable::GpuiSpawned(task);
+ task.run_and_profile();
}
+// Note we can not send through a GpuiRunnable as that would require allocating
+// to keep the pointer alive. So we recreate it here.
extern "C" fn trampoline_compat(runnable: *mut c_void) {
let task = unsafe { Runnable::<()>::from_raw(NonNull::new_unchecked(runnable as *mut ())) };
-
- let location = core::panic::Location::caller();
-
- let start = Instant::now();
- let timing = TaskTiming {
- location,
- start,
- end: None,
- };
- THREAD_TIMINGS.with(|timings| {
- let mut timings = timings.lock();
- let timings = &mut timings.timings;
- if let Some(last_timing) = timings.iter_mut().rev().next() {
- if last_timing.location == timing.location {
- return;
- }
- }
-
- timings.push_back(timing);
- });
-
- task.run();
- let end = Instant::now();
-
- THREAD_TIMINGS.with(|timings| {
- let mut timings = timings.lock();
- let timings = &mut timings.timings;
- let Some(last_timing) = timings.iter_mut().rev().next() else {
- return;
- };
- last_timing.end = Some(end);
- });
+ let task = GpuiRunnable::DependencySpawned(task);
+ task.run_and_profile();
}
@@ -1,4 +1,4 @@
-use crate::{PlatformDispatcher, Priority, RunnableVariant, TaskLabel};
+use crate::{GpuiRunnable, PlatformDispatcher, TaskLabel};
use backtrace::Backtrace;
use collections::{HashMap, HashSet, VecDeque};
use parking::Unparker;
@@ -25,10 +25,10 @@ pub struct TestDispatcher {
struct TestDispatcherState {
random: StdRng,
- foreground: HashMap<TestDispatcherId, VecDeque<RunnableVariant>>,
- background: Vec<RunnableVariant>,
- deprioritized_background: Vec<RunnableVariant>,
- delayed: Vec<(Duration, RunnableVariant)>,
+ foreground: HashMap<TestDispatcherId, VecDeque<GpuiRunnable>>,
+ background: Vec<GpuiRunnable>,
+ deprioritized_background: Vec<GpuiRunnable>,
+ delayed: Vec<(Duration, GpuiRunnable)>,
start_time: Instant,
time: Duration,
is_main_thread: bool,
@@ -176,21 +176,10 @@ impl TestDispatcher {
drop(state);
// todo(localcc): add timings to tests
- match runnable {
- RunnableVariant::Meta(runnable) => {
- if !runnable.metadata().is_app_alive() {
- drop(runnable);
- } else {
- runnable.run();
- }
- }
- RunnableVariant::Compat(runnable) => {
- runnable.run();
- }
- };
-
+ if !runnable.app_dropped() {
+ runnable.run_unprofiled()
+ }
self.state.lock().is_main_thread = was_main_thread;
-
true
}
@@ -292,7 +281,7 @@ impl PlatformDispatcher for TestDispatcher {
state.start_time + state.time
}
- fn dispatch(&self, runnable: RunnableVariant, label: Option<TaskLabel>, _priority: Priority) {
+ fn dispatch(&self, runnable: GpuiRunnable, label: Option<TaskLabel>) {
{
let mut state = self.state.lock();
if label.is_some_and(|label| state.deprioritized_task_labels.contains(&label)) {
@@ -304,7 +293,7 @@ impl PlatformDispatcher for TestDispatcher {
self.unpark_all();
}
- fn dispatch_on_main_thread(&self, runnable: RunnableVariant, _priority: Priority) {
+ fn dispatch_on_main_thread(&self, runnable: GpuiRunnable) {
self.state
.lock()
.foreground
@@ -314,7 +303,7 @@ impl PlatformDispatcher for TestDispatcher {
self.unpark_all();
}
- fn dispatch_after(&self, duration: std::time::Duration, runnable: RunnableVariant) {
+ fn dispatch_after(&self, duration: std::time::Duration, runnable: GpuiRunnable) {
let mut state = self.state.lock();
let next_time = state.time + duration;
let ix = match state.delayed.binary_search_by_key(&next_time, |e| e.0) {
@@ -1,7 +1,7 @@
use std::{
sync::atomic::{AtomicBool, Ordering},
thread::{ThreadId, current},
- time::{Duration, Instant},
+ time::Duration,
};
use anyhow::Context;
@@ -21,14 +21,14 @@ use windows::{
};
use crate::{
- GLOBAL_THREAD_TIMINGS, HWND, PlatformDispatcher, Priority, PriorityQueueSender,
- RealtimePriority, RunnableVariant, SafeHwnd, THREAD_TIMINGS, TaskLabel, TaskTiming,
- ThreadTaskTimings, WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD, profiler,
+ GLOBAL_THREAD_TIMINGS, GpuiRunnable, HWND, PlatformDispatcher, Priority, PriorityQueueSender,
+ RealtimePriority, SafeHwnd, THREAD_TIMINGS, TaskLabel, ThreadTaskTimings,
+ WM_GPUI_TASK_DISPATCHED_ON_MAIN_THREAD,
};
pub(crate) struct WindowsDispatcher {
pub(crate) wake_posted: AtomicBool,
- main_sender: PriorityQueueSender<RunnableVariant>,
+ main_sender: PriorityQueueSender<GpuiRunnable>,
main_thread_id: ThreadId,
pub(crate) platform_window_handle: SafeHwnd,
validation_number: usize,
@@ -36,7 +36,7 @@ pub(crate) struct WindowsDispatcher {
impl WindowsDispatcher {
pub(crate) fn new(
- main_sender: PriorityQueueSender<RunnableVariant>,
+ main_sender: PriorityQueueSender<GpuiRunnable>,
platform_window_handle: HWND,
validation_number: usize,
) -> Self {
@@ -52,11 +52,14 @@ impl WindowsDispatcher {
}
}
- fn dispatch_on_threadpool(&self, priority: WorkItemPriority, runnable: RunnableVariant) {
+ fn dispatch_on_threadpool(&self, runnable: GpuiRunnable, priority: WorkItemPriority) {
let handler = {
- let mut task_wrapper = Some(runnable);
+ let mut runnable = Some(runnable);
WorkItemHandler::new(move |_| {
- Self::execute_runnable(task_wrapper.take().unwrap());
+ runnable
+ .take()
+ .expect("Takes FnMut but only runs once")
+ .run_and_profile();
Ok(())
})
};
@@ -64,54 +67,19 @@ impl WindowsDispatcher {
ThreadPool::RunWithPriorityAsync(&handler, priority).log_err();
}
- fn dispatch_on_threadpool_after(&self, runnable: RunnableVariant, duration: Duration) {
+ fn dispatch_on_threadpool_after(&self, runnable: GpuiRunnable, duration: Duration) {
let handler = {
- let mut task_wrapper = Some(runnable);
+ let mut runnable = Some(runnable);
TimerElapsedHandler::new(move |_| {
- Self::execute_runnable(task_wrapper.take().unwrap());
+ runnable
+ .take()
+ .expect("Takes FnMut but only runs once")
+ .run_and_profile();
Ok(())
})
};
ThreadPoolTimer::CreateTimer(&handler, duration.into()).log_err();
}
-
- #[inline(always)]
- pub(crate) fn execute_runnable(runnable: RunnableVariant) {
- let start = Instant::now();
-
- let mut timing = match runnable {
- RunnableVariant::Meta(runnable) => {
- let location = runnable.metadata().location;
- let timing = TaskTiming {
- location,
- start,
- end: None,
- };
- profiler::add_task_timing(timing);
-
- runnable.run();
-
- timing
- }
- RunnableVariant::Compat(runnable) => {
- let timing = TaskTiming {
- location: core::panic::Location::caller(),
- start,
- end: None,
- };
- profiler::add_task_timing(timing);
-
- runnable.run();
-
- timing
- }
- };
-
- let end = Instant::now();
- timing.end = Some(end);
-
- profiler::add_task_timing(timing);
- }
}
impl PlatformDispatcher for WindowsDispatcher {
@@ -138,22 +106,21 @@ impl PlatformDispatcher for WindowsDispatcher {
current().id() == self.main_thread_id
}
- fn dispatch(&self, runnable: RunnableVariant, label: Option<TaskLabel>, priority: Priority) {
- let priority = match priority {
+ fn dispatch(&self, runnable: GpuiRunnable, label: Option<TaskLabel>) {
+ let priority = match runnable.priority() {
Priority::Realtime(_) => unreachable!(),
Priority::High => WorkItemPriority::High,
Priority::Medium => WorkItemPriority::Normal,
Priority::Low => WorkItemPriority::Low,
};
- self.dispatch_on_threadpool(priority, runnable);
-
+ self.dispatch_on_threadpool(runnable, priority);
if let Some(label) = label {
log::debug!("TaskLabel: {label:?}");
}
}
- fn dispatch_on_main_thread(&self, runnable: RunnableVariant, priority: Priority) {
- match self.main_sender.send(priority, runnable) {
+ fn dispatch_on_main_thread(&self, runnable: GpuiRunnable) {
+ match self.main_sender.send(runnable.priority(), runnable) {
Ok(_) => {
if !self.wake_posted.swap(true, Ordering::AcqRel) {
unsafe {
@@ -181,7 +148,7 @@ impl PlatformDispatcher for WindowsDispatcher {
}
}
- fn dispatch_after(&self, duration: Duration, runnable: RunnableVariant) {
+ fn dispatch_after(&self, duration: Duration, runnable: GpuiRunnable) {
self.dispatch_on_threadpool_after(runnable, duration);
}
@@ -250,7 +250,7 @@ impl WindowsWindowInner {
if wparam.0 == SIZE_MOVE_LOOP_TIMER_ID {
let mut runnables = self.main_receiver.clone().try_iter();
while let Some(Ok(runnable)) = runnables.next() {
- WindowsDispatcher::execute_runnable(runnable);
+ runnable.run_and_profile();
}
self.handle_paint_msg(handle)
} else {
@@ -51,7 +51,7 @@ struct WindowsPlatformInner {
raw_window_handles: std::sync::Weak<RwLock<SmallVec<[SafeHwnd; 4]>>>,
// The below members will never change throughout the entire lifecycle of the app.
validation_number: usize,
- main_receiver: PriorityQueueReceiver<RunnableVariant>,
+ main_receiver: PriorityQueueReceiver<GpuiRunnable>,
dispatcher: Arc<WindowsDispatcher>,
}
@@ -856,7 +856,7 @@ impl WindowsPlatformInner {
}
let mut main_receiver = self.main_receiver.clone();
match main_receiver.try_pop() {
- Ok(Some(runnable)) => WindowsDispatcher::execute_runnable(runnable),
+ Ok(Some(runnable)) => _ = runnable.run_and_profile(),
_ => break 'timeout_loop,
}
}
@@ -868,8 +868,7 @@ impl WindowsPlatformInner {
match main_receiver.try_pop() {
Ok(Some(runnable)) => {
self.dispatcher.wake_posted.store(true, Ordering::Release);
-
- WindowsDispatcher::execute_runnable(runnable);
+ runnable.run_and_profile();
}
_ => break 'tasks,
}
@@ -933,7 +932,7 @@ pub(crate) struct WindowCreationInfo {
pub(crate) windows_version: WindowsVersion,
pub(crate) drop_target_helper: IDropTargetHelper,
pub(crate) validation_number: usize,
- pub(crate) main_receiver: PriorityQueueReceiver<RunnableVariant>,
+ pub(crate) main_receiver: PriorityQueueReceiver<GpuiRunnable>,
pub(crate) platform_window_handle: HWND,
pub(crate) disable_direct_composition: bool,
pub(crate) directx_devices: DirectXDevices,
@@ -946,8 +945,8 @@ struct PlatformWindowCreateContext {
inner: Option<Result<Rc<WindowsPlatformInner>>>,
raw_window_handles: std::sync::Weak<RwLock<SmallVec<[SafeHwnd; 4]>>>,
validation_number: usize,
- main_sender: Option<PriorityQueueSender<RunnableVariant>>,
- main_receiver: Option<PriorityQueueReceiver<RunnableVariant>>,
+ main_sender: Option<PriorityQueueSender<GpuiRunnable>>,
+ main_receiver: Option<PriorityQueueReceiver<GpuiRunnable>>,
directx_devices: Option<DirectXDevices>,
dispatcher: Option<Arc<WindowsDispatcher>>,
}
@@ -82,7 +82,7 @@ pub(crate) struct WindowsWindowInner {
pub(crate) executor: ForegroundExecutor,
pub(crate) windows_version: WindowsVersion,
pub(crate) validation_number: usize,
- pub(crate) main_receiver: PriorityQueueReceiver<RunnableVariant>,
+ pub(crate) main_receiver: PriorityQueueReceiver<GpuiRunnable>,
pub(crate) platform_window_handle: HWND,
pub(crate) parent_hwnd: Option<HWND>,
}
@@ -366,7 +366,7 @@ struct WindowCreateContext {
windows_version: WindowsVersion,
drop_target_helper: IDropTargetHelper,
validation_number: usize,
- main_receiver: PriorityQueueReceiver<RunnableVariant>,
+ main_receiver: PriorityQueueReceiver<GpuiRunnable>,
platform_window_handle: HWND,
appearance: WindowAppearance,
disable_direct_composition: bool,
@@ -12,7 +12,7 @@ mod session;
use std::{sync::Arc, time::Duration};
use async_dispatcher::{Dispatcher, Runnable, set_dispatcher};
-use gpui::{App, PlatformDispatcher, Priority, RunnableVariant};
+use gpui::{App, GpuiRunnable, PlatformDispatcher};
use project::Fs;
pub use runtimelib::ExecutionState;
@@ -46,12 +46,12 @@ fn zed_dispatcher(cx: &mut App) -> impl Dispatcher {
impl Dispatcher for ZedDispatcher {
fn dispatch(&self, runnable: Runnable) {
self.dispatcher
- .dispatch(RunnableVariant::Compat(runnable), None, Priority::default());
+ .dispatch(GpuiRunnable::DependencySpawned(runnable), None);
}
fn dispatch_after(&self, duration: Duration, runnable: Runnable) {
self.dispatcher
- .dispatch_after(duration, RunnableVariant::Compat(runnable));
+ .dispatch_after(duration, GpuiRunnable::DependencySpawned(runnable));
}
}