Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 32 additions & 24 deletions crates/gpui/src/profiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@ use crate::{SharedString, TasksIncluded, WindowId};
#[cfg(feature = "profiler")]
#[doc(hidden)]
pub fn get_all_timings(included: gpui::TasksIncluded) -> Vec<gpui::ThreadTaskTimings> {
let global_thread_timings = GLOBAL_THREAD_TIMINGS.lock();
ThreadTaskTimings::collect(&global_thread_timings, included)
ThreadTaskTimings::collect(upgraded_thread_timings(), included)
}

#[cfg(feature = "profiler")]
Expand All @@ -36,8 +35,7 @@ pub fn get_current_thread_timings(included: TasksIncluded) -> gpui::ThreadTaskTi
#[cfg(feature = "profiler")]
#[doc(hidden)]
pub fn take_all_stats(included: TasksIncluded) -> Vec<gpui::ThreadTaskStatistics> {
let global_timings = GLOBAL_THREAD_TIMINGS.lock();
ThreadTaskStatistics::collect_and_reset(&global_timings, included)
ThreadTaskStatistics::collect_and_reset(upgraded_thread_timings(), included)
}

#[cfg(not(feature = "profiler"))]
Expand Down Expand Up @@ -128,14 +126,13 @@ pub struct ThreadTaskTimings {
}

impl ThreadTaskTimings {
/// Convert global thread timings into their structured format.
pub fn collect(timings: &[GlobalThreadTimings], included: TasksIncluded) -> Vec<Self> {
/// Convert upgraded per-thread timings into their structured format.
pub fn collect(
timings: Vec<(ThreadId, Arc<GuardedTaskTimings>)>,
included: TasksIncluded,
) -> Vec<Self> {
timings
.iter()
.filter_map(|t| match t.timings.upgrade() {
Some(timings) => Some((t.thread_id, timings)),
_ => None,
})
.into_iter()
.map(|(thread_id, timings)| {
let timings = timings.lock();
let thread_name = timings.thread_name.clone();
Expand Down Expand Up @@ -179,15 +176,11 @@ pub struct ThreadTaskStatistics {

impl ThreadTaskStatistics {
pub fn collect_and_reset(
timings: &[GlobalThreadTimings],
timings: Vec<(ThreadId, Arc<GuardedTaskTimings>)>,
include_running: TasksIncluded,
) -> Vec<Self> {
timings
.iter()
.filter_map(|t| match t.timings.upgrade() {
Some(timings) => Some((t.thread_id, timings)),
_ => None,
})
.into_iter()
.map(|(thread_id, timings)| {
let mut timings = timings.lock();
let thread_name = timings.thread_name.clone();
Expand Down Expand Up @@ -511,6 +504,23 @@ impl TaskStatistics {
pub static GLOBAL_THREAD_TIMINGS: spin::Mutex<Vec<GlobalThreadTimings>> =
spin::Mutex::new(Vec::new());

/// Upgrades all live per-thread timing handles, holding the global registry
/// lock only for the duration of the upgrades.
///
/// The upgraded `Arc`s must never be dropped while `GLOBAL_THREAD_TIMINGS` is
/// locked: dropping the last strong reference runs [`ThreadTimings::drop`],
/// which locks `GLOBAL_THREAD_TIMINGS` again and would deadlock the
/// non-reentrant spinlock. A thread exiting concurrently can hand off its last
/// reference to us at any time, so callers of this function process (lock,
/// read, drop) the returned handles only after the global lock is released.
fn upgraded_thread_timings() -> Vec<(ThreadId, Arc<GuardedTaskTimings>)> {
let global_thread_timings = GLOBAL_THREAD_TIMINGS.lock();
global_thread_timings
.iter()
.filter_map(|t| Some((t.thread_id, t.timings.upgrade()?)))
.collect()
}

thread_local! {
#[doc(hidden)]
pub static THREAD_TIMINGS: LazyCell<Arc<GuardedTaskTimings>> = LazyCell::new(|| {
Expand Down Expand Up @@ -679,13 +689,11 @@ pub fn set_trace_enabled(enabled: bool) -> bool {
}

if !enabled {
for global in GLOBAL_THREAD_TIMINGS.lock().iter() {
if let Some(timings) = global.timings.upgrade() {
let mut timings = timings.lock();
timings.timings.clear();
timings.timings.shrink_to_fit();
timings.total_pushed = 0;
}
for (_, timings) in upgraded_thread_timings() {
let mut timings = timings.lock();
timings.timings.clear();
timings.timings.shrink_to_fit();
timings.total_pushed = 0;
}
}
true
Expand Down
2 changes: 1 addition & 1 deletion crates/remote_server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ fs.workspace = true
futures.workspace = true
git.workspace = true
git_hosting_providers.workspace = true
gpui.workspace = true
gpui = { workspace = true, features = ["profiler"] }
gpui_platform.workspace = true
gpui_tokio.workspace = true
http_client.workspace = true
Expand Down
2 changes: 1 addition & 1 deletion crates/zed/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ git_hosting_providers.workspace = true
git_ui = { workspace = true, features = ["call"] }
go_to_line.workspace = true
system_specs.workspace = true
gpui = { workspace = true, features = ["input-latency-histogram"] }
gpui = { workspace = true, features = ["input-latency-histogram", "profiler"] }
gpui_platform = {workspace = true, features=["screen-capture", "font-kit", "wayland", "x11"]}
hdrhistogram.workspace = true
image = { workspace = true, optional = true }
Expand Down
Loading