Compare commits

...

11 Commits

Author SHA1 Message Date
Jakub Konka
3201c4f7f5 Somewhat clean up dependency 2025-10-06 17:04:43 +02:00
Jakub Konka
38e5facb11 Manually annotate each fiber 2025-10-06 16:13:54 +02:00
Jakub Konka
7a37626258 Use new tracy-client fiber helpers 2025-10-05 23:45:45 +02:00
Jakub Konka
6d925345a5 More experiments with futures 2025-10-05 17:13:43 +02:00
Jakub Konka
7bef8880b4 More experiments 2025-10-05 11:34:20 +02:00
Jakub Konka
9b002caa4d tracy: Experiment with tracy fibers 2025-10-03 22:14:19 +02:00
Jakub Konka
860bbdbe78 gpui: Name vsync thread 2025-10-03 22:12:17 +02:00
Jakub Konka
1dcc2102eb tracy: Rename features to profiling-with-tracy and profiling-with-tracy-memory 2025-10-03 22:12:16 +02:00
Jakub Konka
d230a3e199 tracy: Hook up profiling crate 2025-10-03 22:11:46 +02:00
Jakub Konka
ae7ae96d2e tracy: Hook up tracing to tracy for automatic spans 2025-10-03 22:11:45 +02:00
Jakub Konka
10abccbe61 tracy: Hook up tracy CPU and memory profiler behind feature flags 2025-10-03 22:11:44 +02:00
27 changed files with 324 additions and 204 deletions

39
Cargo.lock generated
View File

@@ -3131,6 +3131,7 @@ dependencies = [
"parking_lot",
"paths",
"postage",
"profiling",
"rand 0.9.1",
"regex",
"release_channel",
@@ -4653,6 +4654,7 @@ dependencies = [
"paths",
"picker",
"pretty_assertions",
"profiling",
"project",
"rpc",
"schemars 1.0.1",
@@ -5916,6 +5918,7 @@ dependencies = [
"menu",
"picker",
"pretty_assertions",
"profiling",
"project",
"schemars 1.0.1",
"search",
@@ -6796,6 +6799,7 @@ dependencies = [
"log",
"parking_lot",
"pretty_assertions",
"profiling",
"rand 0.9.1",
"regex",
"rope",
@@ -6808,6 +6812,7 @@ dependencies = [
"text",
"thiserror 2.0.12",
"time",
"tracy-client",
"unindent",
"url",
"util",
@@ -7107,6 +7112,7 @@ dependencies = [
"sum_tree",
"taffy",
"thiserror 2.0.12",
"tracy-client",
"unicode-segmentation",
"usvg",
"util",
@@ -12068,18 +12074,19 @@ dependencies = [
[[package]]
name = "profiling"
version = "1.0.16"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "afbdc74edc00b6f6a218ca6a5364d6226a259d4b8ea1af4a0ea063f27e179f4d"
checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773"
dependencies = [
"profiling-procmacros",
"tracy-client",
]
[[package]]
name = "profiling-procmacros"
version = "1.0.16"
version = "1.0.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a65f2e60fbf1063868558d69c6beacf412dc755f9fc020f514b7955fc914fe30"
checksum = "52717f9a02b6965224f95ca2a81e2e0c5c43baacd28ca057577988930b6c3d5b"
dependencies = [
"quote",
"syn 2.0.101",
@@ -12127,6 +12134,7 @@ dependencies = [
"postage",
"prettier",
"pretty_assertions",
"profiling",
"rand 0.9.1",
"regex",
"release_channel",
@@ -12179,6 +12187,7 @@ dependencies = [
"language",
"menu",
"pretty_assertions",
"profiling",
"project",
"rayon",
"schemars 1.0.1",
@@ -12189,6 +12198,7 @@ dependencies = [
"smallvec",
"telemetry",
"theme",
"tracy-client",
"ui",
"util",
"workspace",
@@ -14482,6 +14492,7 @@ dependencies = [
"log",
"paths",
"pretty_assertions",
"profiling",
"release_channel",
"rust-embed",
"schemars 1.0.1",
@@ -16889,6 +16900,23 @@ dependencies = [
"tracing-serde",
]
[[package]]
name = "tracy-client"
version = "0.18.2"
dependencies = [
"loom",
"once_cell",
"tracy-client-sys",
]
[[package]]
name = "tracy-client-sys"
version = "0.26.1"
dependencies = [
"cc",
"windows-targets 0.48.5",
]
[[package]]
name = "trait-variant"
version = "0.1.2"
@@ -19867,6 +19895,7 @@ dependencies = [
"paths",
"postage",
"pretty_assertions",
"profiling",
"rand 0.9.1",
"rpc",
"serde",
@@ -19876,6 +19905,7 @@ dependencies = [
"smol",
"sum_tree",
"text",
"tracy-client",
"util",
"workspace-hack",
"zlog",
@@ -20335,6 +20365,7 @@ dependencies = [
"time",
"title_bar",
"toolchain_selector",
"tracy-client",
"tree-sitter-md",
"tree-sitter-rust",
"ui",

View File

@@ -595,7 +595,7 @@ portable-pty = "0.9.0"
postage = { version = "0.5", features = ["futures-traits"] }
pretty_assertions = { version = "1.3.0", features = ["unstable"] }
proc-macro2 = "1.0.93"
profiling = "1"
profiling = "1.0.17"
prost = "0.9"
prost-build = "0.9"
prost-types = "0.9"
@@ -667,6 +667,7 @@ tokio = { version = "1" }
tokio-tungstenite = { version = "0.26", features = ["__rustls-tls"] }
toml = "0.8"
tower-http = "0.4.4"
tracy-client = { version = "0.18.2", features = ["fibers"] }
tree-sitter = { version = "0.25.10", features = ["wasm"] }
tree-sitter-bash = "0.25.0"
tree-sitter-c = "0.23"
@@ -772,6 +773,7 @@ features = [
[patch.crates-io]
notify = { git = "https://github.com/zed-industries/notify.git", rev = "bbb9ea5ae52b253e095737847e367c30653a2e96" }
notify-types = { git = "https://github.com/zed-industries/notify.git", rev = "bbb9ea5ae52b253e095737847e367c30653a2e96" }
tracy-client = { path = "../rust_tracy_client/tracy-client" }
windows-capture = { git = "https://github.com/zed-industries/windows-capture.git", rev = "f0d6c1b6691db75461b732f6d5ff56eed002eeb9" }
# Makes the workspace hack crate refer to the local one, but only when you're building locally

View File

@@ -37,6 +37,7 @@ log.workspace = true
parking_lot.workspace = true
paths.workspace = true
postage.workspace = true
profiling.workspace = true
rand.workspace = true
regex.workspace = true
release_channel.workspace = true

View File

@@ -150,6 +150,7 @@ pub fn init_settings(cx: &mut App) {
ProxySettings::register(cx);
}
#[profiling::function]
pub fn init(client: &Arc<Client>, cx: &mut App) {
let client = Arc::downgrade(client);
cx.on_action({

View File

@@ -53,6 +53,7 @@ parse_int.workspace = true
paths.workspace = true
picker.workspace = true
pretty_assertions.workspace = true
profiling.workspace = true
project.workspace = true
rpc.workspace = true
schemars.workspace = true

View File

@@ -114,6 +114,7 @@ actions!(
]
);
#[profiling::function]
pub fn init(cx: &mut App) {
DebuggerSettings::register(cx);
workspace::FollowableViewRegistry::register::<DebugSession>(cx);

View File

@@ -33,6 +33,7 @@ ui.workspace = true
util.workspace = true
workspace.workspace = true
workspace-hack.workspace = true
profiling.workspace = true
[dev-dependencies]
ctor.workspace = true

View File

@@ -122,6 +122,7 @@ impl FileFinder {
);
}
#[profiling::function]
fn open(
workspace: &mut Workspace,
separate_history: bool,

View File

@@ -40,6 +40,8 @@ util.workspace = true
uuid.workspace = true
futures.workspace = true
workspace-hack.workspace = true
profiling.workspace = true
tracy-client.workspace = true
[dev-dependencies]
pretty_assertions.workspace = true

View File

@@ -58,6 +58,7 @@ async fn get_messages_impl(working_directory: &Path, shas: &[Oid]) -> Result<Vec
}
/// Parse the output of `git diff --name-status -z`
#[profiling::function]
pub fn parse_git_diff_name_status(content: &str) -> impl Iterator<Item = (&str, StatusCode)> {
let mut parts = content.split('\0');
std::iter::from_fn(move || {

View File

@@ -681,13 +681,15 @@ impl GitRepository for RealGitRepository {
.boxed()
}
#[profiling::function]
fn load_commit(&self, commit: String, cx: AsyncApp) -> BoxFuture<'_, Result<CommitDiff>> {
let Some(working_directory) = self.repository.lock().workdir().map(ToOwned::to_owned)
else {
return future::ready(Err(anyhow!("no working directory"))).boxed();
};
let git_binary_path = self.any_git_binary_path.clone();
cx.background_spawn(async move {
cx.background_spawn(tracy_client::fiber!("load_commit", async move {
let _zone = tracy_client::span_unchecked!();
let show_output = util::command::new_smol_command(&git_binary_path)
.current_dir(&working_directory)
.args([
@@ -797,7 +799,7 @@ impl GitRepository for RealGitRepository {
}
Ok(CommitDiff { files })
})
}))
.boxed()
}

View File

@@ -72,6 +72,7 @@ screen-capture = [
"scap",
]
windows-manifest = []
profile-with-tracy = ["dep:tracy-client"]
[lib]
path = "src/gpui.rs"
@@ -124,6 +125,7 @@ strum.workspace = true
sum_tree.workspace = true
taffy = "=0.9.0"
thiserror.workspace = true
tracy-client = { workspace = true, optional = true }
util.workspace = true
uuid.workspace = true
waker-fn = "1.2.0"

View File

@@ -129,6 +129,7 @@ pub struct Application(Rc<AppCell>);
impl Application {
/// Builds an app with the given asset source.
#[allow(clippy::new_without_default)]
#[profiling::function]
pub fn new() -> Self {
#[cfg(any(test, feature = "test-support"))]
log::info!("GPUI was compiled in test mode");
@@ -171,6 +172,7 @@ impl Application {
/// Start the application. The provided callback will be called once the
/// app is fully launched.
#[profiling::function]
pub fn run<F>(self, on_finish_launching: F)
where
F: 'static + FnOnce(&mut App),

View File

@@ -53,6 +53,7 @@ impl WindowsDispatcher {
let handler = {
let mut task_wrapper = Some(runnable);
WorkItemHandler::new(move |_| {
profiling::register_thread!();
task_wrapper.take().unwrap().run();
Ok(())
})
@@ -64,6 +65,7 @@ impl WindowsDispatcher {
let handler = {
let mut task_wrapper = Some(runnable);
TimerElapsedHandler::new(move |_| {
profiling::register_thread!();
task_wrapper.take().unwrap().run();
Ok(())
})

View File

@@ -246,6 +246,7 @@ impl WindowsPlatform {
std::thread::Builder::new()
.name("VSyncProvider".to_owned())
.spawn(move || {
profiling::register_thread!("VSyncProvider");
let vsync_provider = VSyncProvider::new();
loop {
vsync_provider.wait_for_vsync();

View File

@@ -25,6 +25,7 @@ test-support = [
"dap/test-support",
"dap_adapters/test-support",
]
profile-with-tracy = ["worktree/profile-with-tracy"]
[dependencies]
aho-corasick.workspace = true
@@ -61,6 +62,7 @@ parking_lot.workspace = true
paths.workspace = true
postage.workspace = true
prettier.workspace = true
profiling.workspace = true
rand.workspace = true
regex.workspace = true
remote.workspace = true

View File

@@ -1000,6 +1000,7 @@ impl Project {
AllAgentServersSettings::register(cx);
}
#[profiling::function]
pub fn init(client: &Arc<Client>, cx: &mut App) {
connection_manager::init(client.clone(), cx);
Self::init_settings(cx);

View File

@@ -36,6 +36,7 @@ serde_json.workspace = true
settings.workspace = true
smallvec.workspace = true
theme.workspace = true
profiling.workspace = true
rayon.workspace = true
ui.workspace = true
util.workspace = true
@@ -45,6 +46,7 @@ workspace.workspace = true
language.workspace = true
zed_actions.workspace = true
telemetry.workspace = true
tracy-client.workspace = true
workspace-hack.workspace = true
[dev-dependencies]

View File

@@ -3175,6 +3175,7 @@ impl ProjectPanel {
}
}
#[profiling::function]
fn update_visible_entries(
&mut self,
new_selected_entry: Option<(WorktreeId, ProjectEntryId)>,
@@ -3206,226 +3207,244 @@ impl ProjectPanel {
let hide_root = settings.hide_root && visible_worktrees.len() == 1;
self.update_visible_entries_task = cx.spawn_in(window, async move |this, cx| {
let new_state = cx
.background_spawn(async move {
for worktree_snapshot in visible_worktrees {
let worktree_id = worktree_snapshot.id();
.background_spawn(tracy_client::fiber!(
"update_visible_entries_task",
async move {
let _zone = tracy_client::span_unchecked!();
for worktree_snapshot in visible_worktrees {
let worktree_id = worktree_snapshot.id();
let expanded_dir_ids = match new_state.expanded_dir_ids.entry(worktree_id) {
hash_map::Entry::Occupied(e) => e.into_mut(),
hash_map::Entry::Vacant(e) => {
// The first time a worktree's root entry becomes available,
// mark that root entry as expanded.
if let Some(entry) = worktree_snapshot.root_entry() {
e.insert(vec![entry.id]).as_slice()
let expanded_dir_ids =
match new_state.expanded_dir_ids.entry(worktree_id) {
hash_map::Entry::Occupied(e) => e.into_mut(),
hash_map::Entry::Vacant(e) => {
// The first time a worktree's root entry becomes available,
// mark that root entry as expanded.
if let Some(entry) = worktree_snapshot.root_entry() {
e.insert(vec![entry.id]).as_slice()
} else {
&[]
}
}
};
let mut new_entry_parent_id = None;
let mut new_entry_kind = EntryKind::Dir;
if let Some(edit_state) = &new_state.edit_state
&& edit_state.worktree_id == worktree_id
&& edit_state.is_new_entry()
{
new_entry_parent_id = Some(edit_state.entry_id);
new_entry_kind = if edit_state.is_dir {
EntryKind::Dir
} else {
&[]
}
EntryKind::File
};
}
};
let mut new_entry_parent_id = None;
let mut new_entry_kind = EntryKind::Dir;
if let Some(edit_state) = &new_state.edit_state
&& edit_state.worktree_id == worktree_id
&& edit_state.is_new_entry()
{
new_entry_parent_id = Some(edit_state.entry_id);
new_entry_kind = if edit_state.is_dir {
EntryKind::Dir
} else {
EntryKind::File
};
}
let mut visible_worktree_entries = Vec::new();
let mut entry_iter = GitTraversal::new(
&repo_snapshots,
worktree_snapshot.entries(true, 0),
);
let mut auto_folded_ancestors = vec![];
let worktree_abs_path = worktree_snapshot.abs_path();
while let Some(entry) = entry_iter.entry() {
if hide_root && Some(entry.entry) == worktree_snapshot.root_entry()
{
if new_entry_parent_id == Some(entry.id) {
visible_worktree_entries.push(Self::create_new_git_entry(
entry.entry,
entry.git_summary,
new_entry_kind,
));
new_entry_parent_id = None;
}
entry_iter.advance();
continue;
}
if auto_collapse_dirs && entry.kind.is_dir() {
auto_folded_ancestors.push(entry.id);
if !new_state.unfolded_dir_ids.contains(&entry.id)
&& let Some(root_path) = worktree_snapshot.root_entry()
{
let mut child_entries =
worktree_snapshot.child_entries(&entry.path);
if let Some(child) = child_entries.next()
&& entry.path != root_path.path
&& child_entries.next().is_none()
&& child.kind.is_dir()
{
entry_iter.advance();
let mut visible_worktree_entries = Vec::new();
let mut entry_iter =
GitTraversal::new(&repo_snapshots, worktree_snapshot.entries(true, 0));
let mut auto_folded_ancestors = vec![];
let worktree_abs_path = worktree_snapshot.abs_path();
while let Some(entry) = entry_iter.entry() {
if hide_root && Some(entry.entry) == worktree_snapshot.root_entry() {
if new_entry_parent_id == Some(entry.id) {
continue;
}
}
let depth = old_ancestors
.get(&entry.id)
.map(|ancestor| ancestor.current_ancestor_depth)
.unwrap_or_default()
.min(auto_folded_ancestors.len());
if let Some(edit_state) = &mut new_state.edit_state
&& edit_state.entry_id == entry.id
{
edit_state.depth = depth;
}
let mut ancestors = std::mem::take(&mut auto_folded_ancestors);
if ancestors.len() > 1 {
ancestors.reverse();
new_state.ancestors.insert(
entry.id,
FoldedAncestors {
current_ancestor_depth: depth,
ancestors,
},
);
}
}
auto_folded_ancestors.clear();
if !hide_gitignore || !entry.is_ignored {
visible_worktree_entries.push(entry.to_owned());
}
let precedes_new_entry =
if let Some(new_entry_id) = new_entry_parent_id {
entry.id == new_entry_id || {
new_state.ancestors.get(&entry.id).is_some_and(
|entries| entries.ancestors.contains(&new_entry_id),
)
}
} else {
false
};
if precedes_new_entry && (!hide_gitignore || !entry.is_ignored) {
visible_worktree_entries.push(Self::create_new_git_entry(
entry.entry,
entry.git_summary,
new_entry_kind,
));
new_entry_parent_id = None;
}
entry_iter.advance();
continue;
}
if auto_collapse_dirs && entry.kind.is_dir() {
auto_folded_ancestors.push(entry.id);
if !new_state.unfolded_dir_ids.contains(&entry.id)
&& let Some(root_path) = worktree_snapshot.root_entry()
{
let mut child_entries =
worktree_snapshot.child_entries(&entry.path);
if let Some(child) = child_entries.next()
&& entry.path != root_path.path
&& child_entries.next().is_none()
&& child.kind.is_dir()
{
entry_iter.advance();
let (depth, chars) = if Some(entry.entry)
== worktree_snapshot.root_entry()
{
let Some(path_name) = worktree_abs_path.file_name() else {
continue;
}
}
let depth = old_ancestors
.get(&entry.id)
.map(|ancestor| ancestor.current_ancestor_depth)
.unwrap_or_default()
.min(auto_folded_ancestors.len());
if let Some(edit_state) = &mut new_state.edit_state
&& edit_state.entry_id == entry.id
{
edit_state.depth = depth;
}
let mut ancestors = std::mem::take(&mut auto_folded_ancestors);
if ancestors.len() > 1 {
ancestors.reverse();
new_state.ancestors.insert(
entry.id,
FoldedAncestors {
current_ancestor_depth: depth,
ancestors,
},
);
}
}
auto_folded_ancestors.clear();
if !hide_gitignore || !entry.is_ignored {
visible_worktree_entries.push(entry.to_owned());
}
let precedes_new_entry = if let Some(new_entry_id) = new_entry_parent_id
{
entry.id == new_entry_id || {
new_state.ancestors.get(&entry.id).is_some_and(|entries| {
entries.ancestors.contains(&new_entry_id)
})
}
} else {
false
};
if precedes_new_entry && (!hide_gitignore || !entry.is_ignored) {
visible_worktree_entries.push(Self::create_new_git_entry(
entry.entry,
entry.git_summary,
new_entry_kind,
));
}
let (depth, chars) = if Some(entry.entry)
== worktree_snapshot.root_entry()
{
let Some(path_name) = worktree_abs_path.file_name() else {
continue;
};
let depth = 0;
(depth, path_name.to_string_lossy().chars().count())
} else if entry.is_file() {
let Some(path_name) = entry
.path
.file_name()
.with_context(|| {
format!("Non-root entry has no file name: {entry:?}")
})
.log_err()
else {
continue;
};
let depth = entry.path.ancestors().count() - 1;
(depth, path_name.chars().count())
} else {
let path = new_state
.ancestors
.get(&entry.id)
.and_then(|ancestors| {
let outermost_ancestor = ancestors.ancestors.last()?;
let root_folded_entry = worktree_snapshot
.entry_for_id(*outermost_ancestor)?
.path
.as_ref();
entry.path.strip_prefix(root_folded_entry).ok().and_then(
|suffix| {
Some(
RelPath::unix(root_folded_entry.file_name()?)
};
let depth = 0;
(depth, path_name.to_string_lossy().chars().count())
} else if entry.is_file() {
let Some(path_name) = entry
.path
.file_name()
.with_context(|| {
format!("Non-root entry has no file name: {entry:?}")
})
.log_err()
else {
continue;
};
let depth = entry.path.ancestors().count() - 1;
(depth, path_name.chars().count())
} else {
let path = new_state
.ancestors
.get(&entry.id)
.and_then(|ancestors| {
let outermost_ancestor = ancestors.ancestors.last()?;
let root_folded_entry = worktree_snapshot
.entry_for_id(*outermost_ancestor)?
.path
.as_ref();
entry
.path
.strip_prefix(root_folded_entry)
.ok()
.and_then(|suffix| {
Some(
RelPath::unix(
root_folded_entry.file_name()?,
)
.unwrap()
.join(suffix),
)
},
)
})
.or_else(|| {
entry.path.file_name().map(|file_name| {
RelPath::unix(file_name).unwrap().into()
)
})
})
})
.unwrap_or_else(|| entry.path.clone());
let depth = path.components().count();
(depth, path.as_unix_str().chars().count())
};
let width_estimate =
item_width_estimate(depth, chars, entry.canonical_path.is_some());
.or_else(|| {
entry.path.file_name().map(|file_name| {
RelPath::unix(file_name).unwrap().into()
})
})
.unwrap_or_else(|| entry.path.clone());
let depth = path.components().count();
(depth, path.as_unix_str().chars().count())
};
let width_estimate = item_width_estimate(
depth,
chars,
entry.canonical_path.is_some(),
);
match max_width_item.as_mut() {
Some((id, worktree_id, width)) => {
if *width < width_estimate {
*id = entry.id;
*worktree_id = worktree_snapshot.id();
*width = width_estimate;
match max_width_item.as_mut() {
Some((id, worktree_id, width)) => {
if *width < width_estimate {
*id = entry.id;
*worktree_id = worktree_snapshot.id();
*width = width_estimate;
}
}
None => {
max_width_item =
Some((entry.id, worktree_snapshot.id(), width_estimate))
}
}
None => {
max_width_item =
Some((entry.id, worktree_snapshot.id(), width_estimate))
if expanded_dir_ids.binary_search(&entry.id).is_err()
&& entry_iter.advance_to_sibling()
{
continue;
}
entry_iter.advance();
}
if expanded_dir_ids.binary_search(&entry.id).is_err()
&& entry_iter.advance_to_sibling()
{
continue;
}
entry_iter.advance();
par_sort_worktree_entries(&mut visible_worktree_entries);
new_state.visible_entries.push(VisibleEntriesForWorktree {
worktree_id,
entries: visible_worktree_entries,
index: OnceCell::new(),
})
}
par_sort_worktree_entries(&mut visible_worktree_entries);
new_state.visible_entries.push(VisibleEntriesForWorktree {
worktree_id,
entries: visible_worktree_entries,
index: OnceCell::new(),
})
}
if let Some((project_entry_id, worktree_id, _)) = max_width_item {
let mut visited_worktrees_length = 0;
let index = new_state
.visible_entries
.iter()
.find_map(|visible_entries| {
if worktree_id == visible_entries.worktree_id {
visible_entries
.entries
.iter()
.position(|entry| entry.id == project_entry_id)
} else {
visited_worktrees_length += visible_entries.entries.len();
None
}
if let Some((project_entry_id, worktree_id, _)) = max_width_item {
let mut visited_worktrees_length = 0;
let index =
new_state
.visible_entries
.iter()
.find_map(|visible_entries| {
if worktree_id == visible_entries.worktree_id {
visible_entries
.entries
.iter()
.position(|entry| entry.id == project_entry_id)
} else {
visited_worktrees_length +=
visible_entries.entries.len();
None
}
});
if let Some(index) = index {
new_state.max_width_item_index =
Some(visited_worktrees_length + index);
}
}
if let Some((worktree_id, entry_id)) = new_selected_entry {
new_state.selection = Some(SelectedEntry {
worktree_id,
entry_id,
});
if let Some(index) = index {
new_state.max_width_item_index = Some(visited_worktrees_length + index);
}
new_state
}
if let Some((worktree_id, entry_id)) = new_selected_entry {
new_state.selection = Some(SelectedEntry {
worktree_id,
entry_id,
});
}
new_state
})
))
.await;
this.update_in(cx, |this, window, cx| {
this.state = new_state;
@@ -4227,6 +4246,7 @@ impl ProjectPanel {
false
}
#[profiling::function]
fn render_entry(
&self,
entry_id: ProjectEntryId,
@@ -5152,6 +5172,7 @@ impl ProjectPanel {
None
}
#[profiling::function]
fn render_sticky_entries(
&self,
child: StickyProjectPanelCandidate,
@@ -5288,6 +5309,7 @@ fn item_width_estimate(depth: usize, item_text_chars: usize, is_symlink: bool) -
}
impl Render for ProjectPanel {
#[profiling::function]
fn render(&mut self, window: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
let has_worktree = !self.state.visible_entries.is_empty();
let project = self.project.read(cx);
@@ -6041,6 +6063,7 @@ pub fn sort_worktree_entries(entries: &mut [impl AsRef<Entry>]) {
entries.sort_by(|lhs, rhs| cmp(lhs, rhs));
}
#[profiling::function]
pub fn par_sort_worktree_entries(entries: &mut Vec<GitEntry>) {
entries.par_sort_by(|lhs, rhs| cmp(lhs, rhs));
}

View File

@@ -25,6 +25,7 @@ gpui.workspace = true
inventory.workspace = true
log.workspace = true
paths.workspace = true
profiling.workspace = true
release_channel.workspace = true
rust-embed.workspace = true
schemars.workspace = true

View File

@@ -77,6 +77,7 @@ impl fmt::Display for WorktreeId {
#[exclude = "*.DS_Store"]
pub struct SettingsAssets;
#[profiling::function]
pub fn init(cx: &mut App) {
let settings = SettingsStore::new(cx, &default_settings());
cx.set_global(settings);

View File

@@ -21,6 +21,7 @@ test-support = [
"text/test-support",
"util/test-support",
]
profile-with-tracy = ["dep:tracy-client"]
[dependencies]
anyhow.workspace = true
@@ -37,6 +38,7 @@ log.workspace = true
parking_lot.workspace = true
paths.workspace = true
postage.workspace = true
profiling.workspace = true
rpc = { workspace = true, features = ["gpui"] }
serde.workspace = true
serde_json.workspace = true
@@ -45,6 +47,7 @@ smallvec.workspace = true
smol.workspace = true
sum_tree.workspace = true
text.workspace = true
tracy-client = { workspace = true, optional = true }
util.workspace = true
workspace-hack.workspace = true

View File

@@ -3083,18 +3083,25 @@ impl language::LocalFile for File {
self.worktree.read(cx).absolutize(&self.path)
}
#[profiling::function]
fn load(&self, cx: &App) -> Task<Result<String>> {
let worktree = self.worktree.read(cx).as_local().unwrap();
let abs_path = worktree.absolutize(&self.path);
let fs = worktree.fs.clone();
cx.background_spawn(async move { fs.load(&abs_path).await })
cx.background_spawn(tracy_client::fiber!("File::load", async move {
fs.load(&abs_path).await
}))
}
#[profiling::function]
fn load_bytes(&self, cx: &App) -> Task<Result<Vec<u8>>> {
let worktree = self.worktree.read(cx).as_local().unwrap();
let abs_path = worktree.absolutize(&self.path);
let fs = worktree.fs.clone();
cx.background_spawn(async move { fs.load_bytes(&abs_path).await })
cx.background_spawn(tracy_client::fiber!("File::load_bytes", async move {
fs.load_bytes(&abs_path).await
}))
}
}

View File

@@ -18,6 +18,10 @@ path = "src/zed-main.rs"
name = "zed"
path = "src/main.rs"
[features]
profile-with-tracy = ["dep:tracy-client", "profiling/profile-with-tracy", "gpui/profile-with-tracy", "project/profile-with-tracy"]
profile-with-tracy-memory = ["profile-with-tracy"]
[dependencies]
acp_tools.workspace = true
activity_indicator.workspace = true
@@ -146,6 +150,7 @@ theme_selector.workspace = true
time.workspace = true
title_bar.workspace = true
toolchain_selector.workspace = true
tracy-client = { workspace = true, optional = true }
ui.workspace = true
ui_input.workspace = true
ui_prompt.workspace = true

View File

@@ -59,10 +59,20 @@ use zed::{
use crate::zed::OpenRequestKind;
#[cfg(feature = "mimalloc")]
#[cfg(all(feature = "mimalloc", not(features = "profile-with-tracy-memory")))]
#[global_allocator]
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;
#[cfg(all(feature = "mimalloc", features = "profile-with-tracy-memory"))]
#[global_allocator]
static GLOBAL: tracy_client::ProfiledAllocator<mimalloc::MiMalloc> =
tracy_client::ProfiledAllocator::new(mimalloc::MiMalloc, 100);
#[cfg(all(not(feature = "mimalloc"), feature = "profile-with-tracy-memory"))]
#[global_allocator]
static GLOBAL: tracy_client::ProfiledAllocator<std::alloc::System> =
tracy_client::ProfiledAllocator::new(std::alloc::System, 100);
fn files_not_created_on_launch(errors: HashMap<io::ErrorKind, Vec<&Path>>) {
let message = "Zed failed to launch";
let error_details = errors
@@ -164,6 +174,7 @@ fn fail_to_open_window(e: anyhow::Error, _cx: &mut App) {
}
}
#[profiling::function]
pub fn main() {
#[cfg(unix)]
util::prevent_root_execution();
@@ -371,6 +382,8 @@ pub fn main() {
});
app.run(move |cx| {
profiling::scope!("app_run");
menu::init();
zed_actions::init();
@@ -1304,6 +1317,7 @@ fn parse_url_arg(arg: &str, cx: &App) -> String {
}
}
#[profiling::function]
fn load_embedded_fonts(cx: &App) {
let asset_source = cx.asset_source();
let font_paths = asset_source.list("fonts").unwrap();
@@ -1386,10 +1400,12 @@ fn eager_load_active_theme_and_icon_theme(fs: Arc<dyn Fs>, cx: &App) {
}
/// Spawns a background task to load the user themes from the themes directory.
#[profiling::function]
fn load_user_themes_in_background(fs: Arc<dyn fs::Fs>, cx: &mut App) {
cx.spawn({
let fs = fs.clone();
async move |cx| {
profiling::scope!("load_user_themes_in_background");
if let Some(theme_registry) = cx.update(|cx| ThemeRegistry::global(cx)).log_err() {
let themes_dir = paths::themes_dir().as_ref();
match fs

View File

@@ -2,6 +2,11 @@
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
pub fn main() {
#[cfg(feature = "profile-with-tracy")]
{
tracy_client::Client::start();
}
// separated out so that the file containing the main function can be imported by other crates,
// while having all gpui resources that are registered in main (primarily actions) initialized
zed::main();

View File

@@ -137,6 +137,7 @@ actions!(
]
);
#[profiling::function]
pub fn init(cx: &mut App) {
#[cfg(target_os = "macos")]
cx.on_action(|_: &Hide, cx| cx.hide());
@@ -1222,6 +1223,7 @@ fn open_log_file(workspace: &mut Workspace, window: &mut Window, cx: &mut Contex
.detach();
}
#[profiling::function]
pub fn handle_settings_file_changes(
mut user_settings_file_rx: mpsc::UnboundedReceiver<String>,
mut global_settings_file_rx: mpsc::UnboundedReceiver<String>,
@@ -1329,6 +1331,7 @@ pub fn handle_settings_file_changes(
.detach();
}
#[profiling::function]
pub fn handle_keymap_file_changes(
mut user_keymap_file_rx: mpsc::UnboundedReceiver<String>,
cx: &mut App,