From b558be7ec60b265837e34d6f9b6f0ef176c20082 Mon Sep 17 00:00:00 2001 From: David Kleingeld Date: Fri, 5 Dec 2025 18:23:06 +0100 Subject: [PATCH] adds tracing for instrumenting non-async functions (#44147) Tracing code is not included in normal release builds Documents how to use them in our performance docs Only the maps and cursors are instrumented atm # Compile times: current main: fresh release build (cargo clean then build --release) 377.34 secs current main: fresh debug build (cargo clean then build ) 89.31 secs tracing tracy: fresh release build (cargo clean then build --release) 374.84 secs tracing tracy: fresh debug build (cargo clean then build ) 88.95 secs tracing tracy: fresh release build with timings (cargo clean then build --release --features tracing) 375.77 secs tracing tracy: fresh debug build with timings (cargo clean then build --features tracing) 90.03 secs Release Notes: - N/A --------- Co-authored-by: localcc --- Cargo.lock | 103 ++- Cargo.toml | 6 + crates/collab/Cargo.toml | 2 +- crates/editor/Cargo.toml | 3 + crates/editor/src/display_map/block_map.rs | 42 + crates/editor/src/display_map/crease_map.rs | 17 + .../src/display_map/custom_highlights.rs | 3 + crates/editor/src/display_map/fold_map.rs | 35 + crates/editor/src/display_map/inlay_map.rs | 28 + crates/editor/src/display_map/invisibles.rs | 1 + crates/editor/src/display_map/tab_map.rs | 27 + crates/editor/src/display_map/wrap_map.rs | 38 + crates/git_ui/Cargo.toml | 7 +- crates/git_ui/src/project_diff.rs | 2 + crates/multi_buffer/Cargo.toml | 5 + crates/multi_buffer/src/multi_buffer.rs | 5 + crates/multi_buffer/src/path_key.rs | 872 +++++++++--------- crates/project/Cargo.toml | 5 + crates/project/src/git_store/branch_diff.rs | 3 + crates/rope/Cargo.toml | 5 + crates/rope/src/rope.rs | 2 + crates/sum_tree/Cargo.toml | 5 + crates/sum_tree/src/cursor.rs | 5 + crates/sum_tree/src/sum_tree.rs | 3 + crates/zed/Cargo.toml | 4 +- crates/zed/src/main.rs | 3 +- crates/ztracing/Cargo.toml | 17 + crates/ztracing/LICENSE-AGPL | 1 + crates/ztracing/LICENSE-APACHE | 1 + crates/ztracing/LICENSE-GPL | 1 + crates/ztracing/build.rs | 9 + crates/ztracing/src/lib.rs | 16 + crates/ztracing_macro/Cargo.toml | 11 + crates/ztracing_macro/LICENSE-AGPL | 1 + crates/ztracing_macro/LICENSE-APACHE | 1 + crates/ztracing_macro/LICENSE-GPL | 1 + crates/ztracing_macro/src/lib.rs | 7 + docs/src/performance.md | 52 +- 38 files changed, 898 insertions(+), 451 deletions(-) create mode 100644 crates/ztracing/Cargo.toml create mode 120000 crates/ztracing/LICENSE-AGPL create mode 120000 crates/ztracing/LICENSE-APACHE create mode 120000 crates/ztracing/LICENSE-GPL create mode 100644 crates/ztracing/build.rs create mode 100644 crates/ztracing/src/lib.rs create mode 100644 crates/ztracing_macro/Cargo.toml create mode 120000 crates/ztracing_macro/LICENSE-AGPL create mode 120000 crates/ztracing_macro/LICENSE-APACHE create mode 120000 crates/ztracing_macro/LICENSE-GPL create mode 100644 crates/ztracing_macro/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 885fbe77fd..a8f0096a7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5344,6 +5344,7 @@ dependencies = [ "text", "theme", "time", + "tracing", "tree-sitter-bash", "tree-sitter-c", "tree-sitter-html", @@ -5363,6 +5364,7 @@ dependencies = [ "workspace", "zed_actions", "zlog", + "ztracing", ] [[package]] @@ -6824,6 +6826,20 @@ dependencies = [ "seq-macro", ] +[[package]] +name = "generator" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows 0.61.3", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -7042,6 +7058,7 @@ dependencies = [ "theme", "time", "time_format", + "tracing", "ui", "unindent", "util", @@ -7051,6 +7068,7 @@ dependencies = [ "zed_actions", "zeroize", "zlog", + "ztracing", ] [[package]] @@ -9373,6 +9391,19 @@ dependencies = [ "value-bag", ] +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + [[package]] name = "loop9" version = "0.1.5" @@ -10043,9 +10074,11 @@ dependencies = [ "sum_tree", "text", "theme", + "tracing", "tree-sitter", "util", "zlog", + "ztracing", ] [[package]] @@ -12400,6 +12433,7 @@ dependencies = [ "terminal", "text", "toml 0.8.23", + "tracing", "unindent", "url", "util", @@ -12409,6 +12443,7 @@ dependencies = [ "worktree", "zeroize", "zlog", + "ztracing", ] [[package]] @@ -13677,9 +13712,11 @@ dependencies = [ "rand 0.9.2", "rayon", "sum_tree", + "tracing", "unicode-segmentation", "util", "zlog", + "ztracing", ] [[package]] @@ -15615,7 +15652,9 @@ dependencies = [ "log", "rand 0.9.2", "rayon", + "tracing", "zlog", + "ztracing", ] [[package]] @@ -17100,9 +17139,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" dependencies = [ "log", "pin-project-lite", @@ -17112,9 +17151,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", @@ -17123,9 +17162,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" dependencies = [ "once_cell", "valuable", @@ -17154,9 +17193,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.20" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" dependencies = [ "matchers", "nu-ansi-term", @@ -17173,6 +17212,38 @@ dependencies = [ "tracing-serde", ] +[[package]] +name = "tracing-tracy" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eaa1852afa96e0fe9e44caa53dc0bd2d9d05e0f2611ce09f97f8677af56e4ba" +dependencies = [ + "tracing-core", + "tracing-subscriber", + "tracy-client", +] + +[[package]] +name = "tracy-client" +version = "0.18.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91d722a05fe49b31fef971c4732a7d4aa6a18283d9ba46abddab35f484872947" +dependencies = [ + "loom", + "once_cell", + "tracy-client-sys", +] + +[[package]] +name = "tracy-client-sys" +version = "0.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fb391ac70462b3097a755618fbf9c8f95ecc1eb379a414f7b46f202ed10db1f" +dependencies = [ + "cc", + "windows-targets 0.52.6", +] + [[package]] name = "trait-variant" version = "0.1.2" @@ -20515,6 +20586,7 @@ dependencies = [ "time", "title_bar", "toolchain_selector", + "tracing", "tree-sitter-md", "tree-sitter-rust", "ui", @@ -20537,6 +20609,7 @@ dependencies = [ "zed_env_vars", "zlog", "zlog_settings", + "ztracing", ] [[package]] @@ -20931,6 +21004,20 @@ dependencies = [ "pkg-config", ] +[[package]] +name = "ztracing" +version = "0.1.0" +dependencies = [ + "tracing", + "tracing-subscriber", + "tracing-tracy", + "ztracing_macro", +] + +[[package]] +name = "ztracing_macro" +version = "0.1.0" + [[package]] name = "zune-core" version = "0.4.12" diff --git a/Cargo.toml b/Cargo.toml index 83bc42e353..858da1dc46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -204,6 +204,8 @@ members = [ "crates/edit_prediction_cli", "crates/zlog", "crates/zlog_settings", + "crates/ztracing", + "crates/ztracing_macro", # # Extensions @@ -434,6 +436,8 @@ zed_env_vars = { path = "crates/zed_env_vars" } edit_prediction = { path = "crates/edit_prediction" } zlog = { path = "crates/zlog" } zlog_settings = { path = "crates/zlog_settings" } +ztracing = { path = "crates/ztracing" } +ztracing_macro = { path = "crates/ztracing_macro" } # # External crates @@ -694,6 +698,8 @@ tree-sitter-ruby = "0.23" tree-sitter-rust = "0.24" tree-sitter-typescript = { git = "https://github.com/zed-industries/tree-sitter-typescript", rev = "e2c53597d6a5d9cf7bbe8dccde576fe1e46c5899" } # https://github.com/tree-sitter/tree-sitter-typescript/pull/347 tree-sitter-yaml = { git = "https://github.com/zed-industries/tree-sitter-yaml", rev = "baff0b51c64ef6a1fb1f8390f3ad6015b83ec13a" } +tracing = "0.1.40" +tracing-tracy = "0.11.4" unicase = "2.6" unicode-script = "0.5.7" unicode-segmentation = "1.10" diff --git a/crates/collab/Cargo.toml b/crates/collab/Cargo.toml index b8a4c03549..79fc21fe33 100644 --- a/crates/collab/Cargo.toml +++ b/crates/collab/Cargo.toml @@ -65,7 +65,7 @@ tokio = { workspace = true, features = ["full"] } toml.workspace = true tower = "0.4" tower-http = { workspace = true, features = ["trace"] } -tracing = "0.1.40" +tracing.workspace = true tracing-subscriber = { version = "0.3.18", features = ["env-filter", "json", "registry", "tracing-log"] } # workaround for https://github.com/tokio-rs/tracing/issues/2927 util.workspace = true uuid.workspace = true diff --git a/crates/editor/Cargo.toml b/crates/editor/Cargo.toml index 94c9fb10f5..f3ed28ab05 100644 --- a/crates/editor/Cargo.toml +++ b/crates/editor/Cargo.toml @@ -84,6 +84,8 @@ tree-sitter-html = { workspace = true, optional = true } tree-sitter-rust = { workspace = true, optional = true } tree-sitter-typescript = { workspace = true, optional = true } tree-sitter-python = { workspace = true, optional = true } +ztracing.workspace = true +tracing.workspace = true unicode-segmentation.workspace = true unicode-script.workspace = true unindent = { workspace = true, optional = true } @@ -94,6 +96,7 @@ uuid.workspace = true vim_mode_setting.workspace = true workspace.workspace = true zed_actions.workspace = true +zlog.workspace = true [dev-dependencies] criterion.workspace = true diff --git a/crates/editor/src/display_map/block_map.rs b/crates/editor/src/display_map/block_map.rs index a674404197..79d06dbf8b 100644 --- a/crates/editor/src/display_map/block_map.rs +++ b/crates/editor/src/display_map/block_map.rs @@ -164,6 +164,7 @@ impl BlockPlacement { } impl BlockPlacement { + #[ztracing::instrument(skip_all)] fn cmp(&self, other: &Self, buffer: &MultiBufferSnapshot) -> Ordering { self.start() .cmp(other.start(), buffer) @@ -171,6 +172,7 @@ impl BlockPlacement { .then_with(|| self.tie_break().cmp(&other.tie_break())) } + #[ztracing::instrument(skip_all)] fn to_wrap_row(&self, wrap_snapshot: &WrapSnapshot) -> Option> { let buffer_snapshot = wrap_snapshot.buffer_snapshot(); match self { @@ -474,6 +476,7 @@ pub struct BlockRows<'a> { } impl BlockMap { + #[ztracing::instrument(skip_all)] pub fn new( wrap_snapshot: WrapSnapshot, buffer_header_height: u32, @@ -503,6 +506,7 @@ impl BlockMap { map } + #[ztracing::instrument(skip_all)] pub fn read(&self, wrap_snapshot: WrapSnapshot, edits: WrapPatch) -> BlockMapReader<'_> { self.sync(&wrap_snapshot, edits); *self.wrap_snapshot.borrow_mut() = wrap_snapshot.clone(); @@ -518,13 +522,17 @@ impl BlockMap { } } + #[ztracing::instrument(skip_all)] pub fn write(&mut self, wrap_snapshot: WrapSnapshot, edits: WrapPatch) -> BlockMapWriter<'_> { self.sync(&wrap_snapshot, edits); *self.wrap_snapshot.borrow_mut() = wrap_snapshot; BlockMapWriter(self) } + #[ztracing::instrument(skip_all, fields(edits))] fn sync(&self, wrap_snapshot: &WrapSnapshot, mut edits: WrapPatch) { + let _timer = zlog::time!("BlockMap::sync").warn_if_gt(std::time::Duration::from_millis(50)); + let buffer = wrap_snapshot.buffer_snapshot(); // Handle changing the last excerpt if it is empty. @@ -784,6 +792,7 @@ impl BlockMap { *transforms = new_transforms; } + #[ztracing::instrument(skip_all)] pub fn replace_blocks(&mut self, mut renderers: HashMap) { for block in &mut self.custom_blocks { if let Some(render) = renderers.remove(&block.id) { @@ -793,6 +802,7 @@ impl BlockMap { } /// Guarantees that `wrap_row_for` is called with points in increasing order. + #[ztracing::instrument(skip_all)] fn header_and_footer_blocks<'a, R, T>( &'a self, buffer: &'a multi_buffer::MultiBufferSnapshot, @@ -880,6 +890,7 @@ impl BlockMap { }) } + #[ztracing::instrument(skip_all)] fn sort_blocks(blocks: &mut Vec<(BlockPlacement, Block)>) { blocks.sort_unstable_by(|(placement_a, block_a), (placement_b, block_b)| { placement_a @@ -1016,6 +1027,7 @@ impl DerefMut for BlockMapReader<'_> { } impl BlockMapReader<'_> { + #[ztracing::instrument(skip_all)] pub fn row_for_block(&self, block_id: CustomBlockId) -> Option { let block = self.blocks.iter().find(|block| block.id == block_id)?; let buffer_row = block @@ -1054,6 +1066,7 @@ impl BlockMapReader<'_> { } impl BlockMapWriter<'_> { + #[ztracing::instrument(skip_all)] pub fn insert( &mut self, blocks: impl IntoIterator>, @@ -1120,6 +1133,7 @@ impl BlockMapWriter<'_> { ids } + #[ztracing::instrument(skip_all)] pub fn resize(&mut self, mut heights: HashMap) { let wrap_snapshot = &*self.0.wrap_snapshot.borrow(); let buffer = wrap_snapshot.buffer_snapshot(); @@ -1172,6 +1186,7 @@ impl BlockMapWriter<'_> { self.0.sync(wrap_snapshot, edits); } + #[ztracing::instrument(skip_all)] pub fn remove(&mut self, block_ids: HashSet) { let wrap_snapshot = &*self.0.wrap_snapshot.borrow(); let buffer = wrap_snapshot.buffer_snapshot(); @@ -1217,6 +1232,7 @@ impl BlockMapWriter<'_> { self.0.sync(wrap_snapshot, edits); } + #[ztracing::instrument(skip_all)] pub fn remove_intersecting_replace_blocks( &mut self, ranges: impl IntoIterator>, @@ -1239,6 +1255,7 @@ impl BlockMapWriter<'_> { self.0.buffers_with_disabled_headers.insert(buffer_id); } + #[ztracing::instrument(skip_all)] pub fn fold_buffers( &mut self, buffer_ids: impl IntoIterator, @@ -1248,6 +1265,7 @@ impl BlockMapWriter<'_> { self.fold_or_unfold_buffers(true, buffer_ids, multi_buffer, cx); } + #[ztracing::instrument(skip_all)] pub fn unfold_buffers( &mut self, buffer_ids: impl IntoIterator, @@ -1257,6 +1275,7 @@ impl BlockMapWriter<'_> { self.fold_or_unfold_buffers(false, buffer_ids, multi_buffer, cx); } + #[ztracing::instrument(skip_all)] fn fold_or_unfold_buffers( &mut self, fold: bool, @@ -1292,6 +1311,7 @@ impl BlockMapWriter<'_> { self.0.sync(&wrap_snapshot, edits); } + #[ztracing::instrument(skip_all)] fn blocks_intersecting_buffer_range( &self, range: Range, @@ -1326,6 +1346,7 @@ impl BlockMapWriter<'_> { impl BlockSnapshot { #[cfg(test)] + #[ztracing::instrument(skip_all)] pub fn text(&self) -> String { self.chunks( BlockRow(0)..self.transforms.summary().output_rows, @@ -1337,6 +1358,7 @@ impl BlockSnapshot { .collect() } + #[ztracing::instrument(skip_all)] pub(crate) fn chunks<'a>( &'a self, rows: Range, @@ -1378,6 +1400,7 @@ impl BlockSnapshot { } } + #[ztracing::instrument(skip_all)] pub(super) fn row_infos(&self, start_row: BlockRow) -> BlockRows<'_> { let mut cursor = self.transforms.cursor::>(()); cursor.seek(&start_row, Bias::Right); @@ -1399,6 +1422,7 @@ impl BlockSnapshot { } } + #[ztracing::instrument(skip_all)] pub fn blocks_in_range( &self, rows: Range, @@ -1432,6 +1456,7 @@ impl BlockSnapshot { }) } + #[ztracing::instrument(skip_all)] pub(crate) fn sticky_header_excerpt(&self, position: f64) -> Option> { let top_row = position as u32; let mut cursor = self.transforms.cursor::(()); @@ -1455,6 +1480,7 @@ impl BlockSnapshot { None } + #[ztracing::instrument(skip_all)] pub fn block_for_id(&self, block_id: BlockId) -> Option { let buffer = self.wrap_snapshot.buffer_snapshot(); let wrap_point = match block_id { @@ -1491,6 +1517,7 @@ impl BlockSnapshot { None } + #[ztracing::instrument(skip_all)] pub fn max_point(&self) -> BlockPoint { let row = self .transforms @@ -1500,10 +1527,12 @@ impl BlockSnapshot { BlockPoint::new(row, self.line_len(row)) } + #[ztracing::instrument(skip_all)] pub fn longest_row(&self) -> BlockRow { self.transforms.summary().longest_row } + #[ztracing::instrument(skip_all)] pub fn longest_row_in_range(&self, range: Range) -> BlockRow { let mut cursor = self.transforms.cursor::>(()); cursor.seek(&range.start, Bias::Right); @@ -1555,6 +1584,7 @@ impl BlockSnapshot { longest_row } + #[ztracing::instrument(skip_all)] pub(super) fn line_len(&self, row: BlockRow) -> u32 { let (start, _, item) = self.transforms @@ -1574,11 +1604,13 @@ impl BlockSnapshot { } } + #[ztracing::instrument(skip_all)] pub(super) fn is_block_line(&self, row: BlockRow) -> bool { let (_, _, item) = self.transforms.find::((), &row, Bias::Right); item.is_some_and(|t| t.block.is_some()) } + #[ztracing::instrument(skip_all)] pub(super) fn is_folded_buffer_header(&self, row: BlockRow) -> bool { let (_, _, item) = self.transforms.find::((), &row, Bias::Right); let Some(transform) = item else { @@ -1587,6 +1619,7 @@ impl BlockSnapshot { matches!(transform.block, Some(Block::FoldedBuffer { .. })) } + #[ztracing::instrument(skip_all)] pub(super) fn is_line_replaced(&self, row: MultiBufferRow) -> bool { let wrap_point = self .wrap_snapshot @@ -1602,6 +1635,7 @@ impl BlockSnapshot { }) } + #[ztracing::instrument(skip_all)] pub fn clip_point(&self, point: BlockPoint, bias: Bias) -> BlockPoint { let mut cursor = self.transforms.cursor::>(()); cursor.seek(&BlockRow(point.row), Bias::Right); @@ -1663,6 +1697,7 @@ impl BlockSnapshot { } } + #[ztracing::instrument(skip_all)] pub fn to_block_point(&self, wrap_point: WrapPoint) -> BlockPoint { let (start, _, item) = self.transforms.find::, _>( (), @@ -1684,6 +1719,7 @@ impl BlockSnapshot { } } + #[ztracing::instrument(skip_all)] pub fn to_wrap_point(&self, block_point: BlockPoint, bias: Bias) -> WrapPoint { let (start, end, item) = self.transforms.find::, _>( (), @@ -1719,6 +1755,7 @@ impl BlockSnapshot { impl BlockChunks<'_> { /// Go to the next transform + #[ztracing::instrument(skip_all)] fn advance(&mut self) { self.input_chunk = Chunk::default(); self.transforms.next(); @@ -1759,6 +1796,7 @@ pub struct StickyHeaderExcerpt<'a> { impl<'a> Iterator for BlockChunks<'a> { type Item = Chunk<'a>; + #[ztracing::instrument(skip_all)] fn next(&mut self) -> Option { if self.output_row >= self.max_output_row { return None; @@ -1858,6 +1896,7 @@ impl<'a> Iterator for BlockChunks<'a> { impl Iterator for BlockRows<'_> { type Item = RowInfo; + #[ztracing::instrument(skip_all)] fn next(&mut self) -> Option { if self.started { self.output_row.0 += 1; @@ -1960,14 +1999,17 @@ impl DerefMut for BlockContext<'_, '_> { } impl CustomBlock { + #[ztracing::instrument(skip_all)] pub fn render(&self, cx: &mut BlockContext) -> AnyElement { self.render.lock()(cx) } + #[ztracing::instrument(skip_all)] pub fn start(&self) -> Anchor { *self.placement.start() } + #[ztracing::instrument(skip_all)] pub fn end(&self) -> Anchor { *self.placement.end() } diff --git a/crates/editor/src/display_map/crease_map.rs b/crates/editor/src/display_map/crease_map.rs index a68c278867..8f4a3781f4 100644 --- a/crates/editor/src/display_map/crease_map.rs +++ b/crates/editor/src/display_map/crease_map.rs @@ -19,6 +19,7 @@ pub struct CreaseMap { } impl CreaseMap { + #[ztracing::instrument(skip_all)] pub fn new(snapshot: &MultiBufferSnapshot) -> Self { CreaseMap { snapshot: CreaseSnapshot::new(snapshot), @@ -40,11 +41,13 @@ impl CreaseSnapshot { } } + #[ztracing::instrument(skip_all)] pub fn creases(&self) -> impl Iterator)> { self.creases.iter().map(|item| (item.id, &item.crease)) } /// Returns the first Crease starting on the specified buffer row. + #[ztracing::instrument(skip_all)] pub fn query_row<'a>( &'a self, row: MultiBufferRow, @@ -69,6 +72,7 @@ impl CreaseSnapshot { None } + #[ztracing::instrument(skip_all)] pub fn creases_in_range<'a>( &'a self, range: Range, @@ -95,6 +99,7 @@ impl CreaseSnapshot { }) } + #[ztracing::instrument(skip_all)] pub fn crease_items_with_offsets( &self, snapshot: &MultiBufferSnapshot, @@ -156,6 +161,7 @@ pub struct CreaseMetadata { } impl Crease { + #[ztracing::instrument(skip_all)] pub fn simple(range: Range, placeholder: FoldPlaceholder) -> Self { Crease::Inline { range, @@ -166,6 +172,7 @@ impl Crease { } } + #[ztracing::instrument(skip_all)] pub fn block(range: Range, height: u32, style: BlockStyle, render: RenderBlock) -> Self { Self::Block { range, @@ -177,6 +184,7 @@ impl Crease { } } + #[ztracing::instrument(skip_all)] pub fn inline( range: Range, placeholder: FoldPlaceholder, @@ -216,6 +224,7 @@ impl Crease { } } + #[ztracing::instrument(skip_all)] pub fn with_metadata(self, metadata: CreaseMetadata) -> Self { match self { Crease::Inline { @@ -235,6 +244,7 @@ impl Crease { } } + #[ztracing::instrument(skip_all)] pub fn range(&self) -> &Range { match self { Crease::Inline { range, .. } => range, @@ -242,6 +252,7 @@ impl Crease { } } + #[ztracing::instrument(skip_all)] pub fn metadata(&self) -> Option<&CreaseMetadata> { match self { Self::Inline { metadata, .. } => metadata.as_ref(), @@ -287,6 +298,7 @@ impl CreaseMap { self.snapshot.clone() } + #[ztracing::instrument(skip_all)] pub fn insert( &mut self, creases: impl IntoIterator>, @@ -312,6 +324,7 @@ impl CreaseMap { new_ids } + #[ztracing::instrument(skip_all)] pub fn remove( &mut self, ids: impl IntoIterator, @@ -379,6 +392,7 @@ impl sum_tree::Summary for ItemSummary { impl sum_tree::Item for CreaseItem { type Summary = ItemSummary; + #[ztracing::instrument(skip_all)] fn summary(&self, _cx: &MultiBufferSnapshot) -> Self::Summary { ItemSummary { range: self.crease.range().clone(), @@ -388,12 +402,14 @@ impl sum_tree::Item for CreaseItem { /// Implements `SeekTarget` for `Range` to enable seeking within a `SumTree` of `CreaseItem`s. impl SeekTarget<'_, ItemSummary, ItemSummary> for Range { + #[ztracing::instrument(skip_all)] fn cmp(&self, cursor_location: &ItemSummary, snapshot: &MultiBufferSnapshot) -> Ordering { AnchorRangeExt::cmp(self, &cursor_location.range, snapshot) } } impl SeekTarget<'_, ItemSummary, ItemSummary> for Anchor { + #[ztracing::instrument(skip_all)] fn cmp(&self, other: &ItemSummary, snapshot: &MultiBufferSnapshot) -> Ordering { self.cmp(&other.range.start, snapshot) } @@ -461,6 +477,7 @@ mod test { } #[gpui::test] + #[ztracing::instrument(skip_all)] fn test_creases_in_range(cx: &mut App) { let text = "line1\nline2\nline3\nline4\nline5\nline6\nline7"; let buffer = MultiBuffer::build_simple(text, cx); diff --git a/crates/editor/src/display_map/custom_highlights.rs b/crates/editor/src/display_map/custom_highlights.rs index a40d1adc82..c9202280bf 100644 --- a/crates/editor/src/display_map/custom_highlights.rs +++ b/crates/editor/src/display_map/custom_highlights.rs @@ -30,6 +30,7 @@ struct HighlightEndpoint { } impl<'a> CustomHighlightsChunks<'a> { + #[ztracing::instrument(skip_all)] pub fn new( range: Range, language_aware: bool, @@ -51,6 +52,7 @@ impl<'a> CustomHighlightsChunks<'a> { } } + #[ztracing::instrument(skip_all)] pub fn seek(&mut self, new_range: Range) { self.highlight_endpoints = create_highlight_endpoints(&new_range, self.text_highlights, self.multibuffer_snapshot); @@ -108,6 +110,7 @@ fn create_highlight_endpoints( impl<'a> Iterator for CustomHighlightsChunks<'a> { type Item = Chunk<'a>; + #[ztracing::instrument(skip_all)] fn next(&mut self) -> Option { let mut next_highlight_endpoint = MultiBufferOffset(usize::MAX); while let Some(endpoint) = self.highlight_endpoints.peek().copied() { diff --git a/crates/editor/src/display_map/fold_map.rs b/crates/editor/src/display_map/fold_map.rs index 2d37dea38a..bb0d6885ac 100644 --- a/crates/editor/src/display_map/fold_map.rs +++ b/crates/editor/src/display_map/fold_map.rs @@ -99,6 +99,7 @@ impl FoldPoint { &mut self.0.column } + #[ztracing::instrument(skip_all)] pub fn to_inlay_point(self, snapshot: &FoldSnapshot) -> InlayPoint { let (start, _, _) = snapshot .transforms @@ -107,6 +108,7 @@ impl FoldPoint { InlayPoint(start.1.0 + overshoot) } + #[ztracing::instrument(skip_all)] pub fn to_offset(self, snapshot: &FoldSnapshot) -> FoldOffset { let (start, _, item) = snapshot .transforms @@ -138,6 +140,7 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for FoldPoint { pub(crate) struct FoldMapWriter<'a>(&'a mut FoldMap); impl FoldMapWriter<'_> { + #[ztracing::instrument(skip_all)] pub(crate) fn fold( &mut self, ranges: impl IntoIterator, FoldPlaceholder)>, @@ -202,6 +205,7 @@ impl FoldMapWriter<'_> { } /// Removes any folds with the given ranges. + #[ztracing::instrument(skip_all)] pub(crate) fn remove_folds( &mut self, ranges: impl IntoIterator>, @@ -215,6 +219,7 @@ impl FoldMapWriter<'_> { } /// Removes any folds whose ranges intersect the given ranges. + #[ztracing::instrument(skip_all)] pub(crate) fn unfold_intersecting( &mut self, ranges: impl IntoIterator>, @@ -225,6 +230,7 @@ impl FoldMapWriter<'_> { /// Removes any folds that intersect the given ranges and for which the given predicate /// returns true. + #[ztracing::instrument(skip_all)] fn remove_folds_with( &mut self, ranges: impl IntoIterator>, @@ -277,6 +283,7 @@ impl FoldMapWriter<'_> { (self.0.snapshot.clone(), edits) } + #[ztracing::instrument(skip_all)] pub(crate) fn update_fold_widths( &mut self, new_widths: impl IntoIterator, @@ -326,6 +333,7 @@ pub struct FoldMap { } impl FoldMap { + #[ztracing::instrument(skip_all)] pub fn new(inlay_snapshot: InlaySnapshot) -> (Self, FoldSnapshot) { let this = Self { snapshot: FoldSnapshot { @@ -350,6 +358,7 @@ impl FoldMap { (this, snapshot) } + #[ztracing::instrument(skip_all)] pub fn read( &mut self, inlay_snapshot: InlaySnapshot, @@ -360,6 +369,7 @@ impl FoldMap { (self.snapshot.clone(), edits) } + #[ztracing::instrument(skip_all)] pub(crate) fn write( &mut self, inlay_snapshot: InlaySnapshot, @@ -369,6 +379,7 @@ impl FoldMap { (FoldMapWriter(self), snapshot, edits) } + #[ztracing::instrument(skip_all)] fn check_invariants(&self) { if cfg!(test) { assert_eq!( @@ -398,6 +409,7 @@ impl FoldMap { } } + #[ztracing::instrument(skip_all)] fn sync( &mut self, inlay_snapshot: InlaySnapshot, @@ -645,6 +657,7 @@ impl FoldSnapshot { &self.inlay_snapshot.buffer } + #[ztracing::instrument(skip_all)] fn fold_width(&self, fold_id: &FoldId) -> Option { self.fold_metadata_by_id.get(fold_id)?.width } @@ -665,6 +678,7 @@ impl FoldSnapshot { self.folds.items(&self.inlay_snapshot.buffer).len() } + #[ztracing::instrument(skip_all)] pub fn text_summary_for_range(&self, range: Range) -> MBTextSummary { let mut summary = MBTextSummary::default(); @@ -718,6 +732,7 @@ impl FoldSnapshot { summary } + #[ztracing::instrument(skip_all)] pub fn to_fold_point(&self, point: InlayPoint, bias: Bias) -> FoldPoint { let (start, end, item) = self .transforms @@ -734,6 +749,7 @@ impl FoldSnapshot { } } + #[ztracing::instrument(skip_all)] pub fn fold_point_cursor(&self) -> FoldPointCursor<'_> { let cursor = self .transforms @@ -741,10 +757,12 @@ impl FoldSnapshot { FoldPointCursor { cursor } } + #[ztracing::instrument(skip_all)] pub fn len(&self) -> FoldOffset { FoldOffset(self.transforms.summary().output.len) } + #[ztracing::instrument(skip_all)] pub fn line_len(&self, row: u32) -> u32 { let line_start = FoldPoint::new(row, 0).to_offset(self).0; let line_end = if row >= self.max_point().row() { @@ -755,6 +773,7 @@ impl FoldSnapshot { (line_end - line_start) as u32 } + #[ztracing::instrument(skip_all)] pub fn row_infos(&self, start_row: u32) -> FoldRows<'_> { if start_row > self.transforms.summary().output.lines.row { panic!("invalid display row {}", start_row); @@ -777,6 +796,7 @@ impl FoldSnapshot { } } + #[ztracing::instrument(skip_all)] pub fn max_point(&self) -> FoldPoint { FoldPoint(self.transforms.summary().output.lines) } @@ -786,6 +806,7 @@ impl FoldSnapshot { self.transforms.summary().output.longest_row } + #[ztracing::instrument(skip_all)] pub fn folds_in_range(&self, range: Range) -> impl Iterator where T: ToOffset, @@ -800,6 +821,7 @@ impl FoldSnapshot { }) } + #[ztracing::instrument(skip_all)] pub fn intersects_fold(&self, offset: T) -> bool where T: ToOffset, @@ -812,6 +834,7 @@ impl FoldSnapshot { item.is_some_and(|t| t.placeholder.is_some()) } + #[ztracing::instrument(skip_all)] pub fn is_line_folded(&self, buffer_row: MultiBufferRow) -> bool { let mut inlay_point = self .inlay_snapshot @@ -840,6 +863,7 @@ impl FoldSnapshot { } } + #[ztracing::instrument(skip_all)] pub(crate) fn chunks<'a>( &'a self, range: Range, @@ -884,6 +908,7 @@ impl FoldSnapshot { } } + #[ztracing::instrument(skip_all)] pub fn chars_at(&self, start: FoldPoint) -> impl '_ + Iterator { self.chunks( start.to_offset(self)..self.len(), @@ -893,6 +918,7 @@ impl FoldSnapshot { .flat_map(|chunk| chunk.text.chars()) } + #[ztracing::instrument(skip_all)] pub fn chunks_at(&self, start: FoldPoint) -> FoldChunks<'_> { self.chunks( start.to_offset(self)..self.len(), @@ -902,6 +928,7 @@ impl FoldSnapshot { } #[cfg(test)] + #[ztracing::instrument(skip_all)] pub fn clip_offset(&self, offset: FoldOffset, bias: Bias) -> FoldOffset { if offset > self.len() { self.len() @@ -910,6 +937,7 @@ impl FoldSnapshot { } } + #[ztracing::instrument(skip_all)] pub fn clip_point(&self, point: FoldPoint, bias: Bias) -> FoldPoint { let (start, end, item) = self .transforms @@ -939,6 +967,7 @@ pub struct FoldPointCursor<'transforms> { } impl FoldPointCursor<'_> { + #[ztracing::instrument(skip_all)] pub fn map(&mut self, point: InlayPoint, bias: Bias) -> FoldPoint { let cursor = &mut self.cursor; if cursor.did_seek() { @@ -1267,6 +1296,7 @@ pub struct FoldRows<'a> { } impl FoldRows<'_> { + #[ztracing::instrument(skip_all)] pub(crate) fn seek(&mut self, row: u32) { let fold_point = FoldPoint::new(row, 0); self.cursor.seek(&fold_point, Bias::Left); @@ -1280,6 +1310,7 @@ impl FoldRows<'_> { impl Iterator for FoldRows<'_> { type Item = RowInfo; + #[ztracing::instrument(skip_all)] fn next(&mut self) -> Option { let mut traversed_fold = false; while self.fold_point > self.cursor.end().0 { @@ -1391,6 +1422,7 @@ pub struct FoldChunks<'a> { } impl FoldChunks<'_> { + #[ztracing::instrument(skip_all)] pub(crate) fn seek(&mut self, range: Range) { self.transform_cursor.seek(&range.start, Bias::Right); @@ -1425,6 +1457,7 @@ impl FoldChunks<'_> { impl<'a> Iterator for FoldChunks<'a> { type Item = Chunk<'a>; + #[ztracing::instrument(skip_all)] fn next(&mut self) -> Option { if self.output_offset >= self.max_output_offset { return None; @@ -1524,6 +1557,7 @@ impl<'a> Iterator for FoldChunks<'a> { pub struct FoldOffset(pub MultiBufferOffset); impl FoldOffset { + #[ztracing::instrument(skip_all)] pub fn to_point(self, snapshot: &FoldSnapshot) -> FoldPoint { let (start, _, item) = snapshot .transforms @@ -1539,6 +1573,7 @@ impl FoldOffset { } #[cfg(test)] + #[ztracing::instrument(skip_all)] pub fn to_inlay_offset(self, snapshot: &FoldSnapshot) -> InlayOffset { let (start, _, _) = snapshot .transforms diff --git a/crates/editor/src/display_map/inlay_map.rs b/crates/editor/src/display_map/inlay_map.rs index 73174c3018..d85f761a82 100644 --- a/crates/editor/src/display_map/inlay_map.rs +++ b/crates/editor/src/display_map/inlay_map.rs @@ -52,6 +52,7 @@ enum Transform { impl sum_tree::Item for Transform { type Summary = TransformSummary; + #[ztracing::instrument(skip_all)] fn summary(&self, _: ()) -> Self::Summary { match self { Transform::Isomorphic(summary) => TransformSummary { @@ -228,6 +229,7 @@ pub struct InlayChunk<'a> { } impl InlayChunks<'_> { + #[ztracing::instrument(skip_all)] pub fn seek(&mut self, new_range: Range) { self.transforms.seek(&new_range.start, Bias::Right); @@ -248,6 +250,7 @@ impl InlayChunks<'_> { impl<'a> Iterator for InlayChunks<'a> { type Item = InlayChunk<'a>; + #[ztracing::instrument(skip_all)] fn next(&mut self) -> Option { if self.output_offset == self.max_output_offset { return None; @@ -441,6 +444,7 @@ impl<'a> Iterator for InlayChunks<'a> { } impl InlayBufferRows<'_> { + #[ztracing::instrument(skip_all)] pub fn seek(&mut self, row: u32) { let inlay_point = InlayPoint::new(row, 0); self.transforms.seek(&inlay_point, Bias::Left); @@ -465,6 +469,7 @@ impl InlayBufferRows<'_> { impl Iterator for InlayBufferRows<'_> { type Item = RowInfo; + #[ztracing::instrument(skip_all)] fn next(&mut self) -> Option { let buffer_row = if self.inlay_row == 0 { self.buffer_rows.next().unwrap() @@ -494,6 +499,7 @@ impl InlayPoint { } impl InlayMap { + #[ztracing::instrument(skip_all)] pub fn new(buffer: MultiBufferSnapshot) -> (Self, InlaySnapshot) { let version = 0; let snapshot = InlaySnapshot { @@ -511,6 +517,7 @@ impl InlayMap { ) } + #[ztracing::instrument(skip_all)] pub fn sync( &mut self, buffer_snapshot: MultiBufferSnapshot, @@ -643,6 +650,7 @@ impl InlayMap { } } + #[ztracing::instrument(skip_all)] pub fn splice( &mut self, to_remove: &[InlayId], @@ -693,11 +701,13 @@ impl InlayMap { (snapshot, edits) } + #[ztracing::instrument(skip_all)] pub fn current_inlays(&self) -> impl Iterator { self.inlays.iter() } #[cfg(test)] + #[ztracing::instrument(skip_all)] pub(crate) fn randomly_mutate( &mut self, next_inlay_id: &mut usize, @@ -766,6 +776,7 @@ impl InlayMap { } impl InlaySnapshot { + #[ztracing::instrument(skip_all)] pub fn to_point(&self, offset: InlayOffset) -> InlayPoint { let (start, _, item) = self.transforms.find:: InlayOffset { InlayOffset(self.transforms.summary().output.len) } + #[ztracing::instrument(skip_all)] pub fn max_point(&self) -> InlayPoint { InlayPoint(self.transforms.summary().output.lines) } + #[ztracing::instrument(skip_all, fields(point))] pub fn to_offset(&self, point: InlayPoint) -> InlayOffset { let (start, _, item) = self .transforms @@ -817,6 +831,7 @@ impl InlaySnapshot { None => self.len(), } } + #[ztracing::instrument(skip_all)] pub fn to_buffer_point(&self, point: InlayPoint) -> Point { let (start, _, item) = self.transforms @@ -830,6 +845,7 @@ impl InlaySnapshot { None => self.buffer.max_point(), } } + #[ztracing::instrument(skip_all)] pub fn to_buffer_offset(&self, offset: InlayOffset) -> MultiBufferOffset { let (start, _, item) = self .transforms @@ -844,6 +860,7 @@ impl InlaySnapshot { } } + #[ztracing::instrument(skip_all)] pub fn to_inlay_offset(&self, offset: MultiBufferOffset) -> InlayOffset { let mut cursor = self .transforms @@ -880,10 +897,12 @@ impl InlaySnapshot { } } + #[ztracing::instrument(skip_all)] pub fn to_inlay_point(&self, point: Point) -> InlayPoint { self.inlay_point_cursor().map(point) } + #[ztracing::instrument(skip_all)] pub fn inlay_point_cursor(&self) -> InlayPointCursor<'_> { let cursor = self.transforms.cursor::>(()); InlayPointCursor { @@ -892,6 +911,7 @@ impl InlaySnapshot { } } + #[ztracing::instrument(skip_all)] pub fn clip_point(&self, mut point: InlayPoint, mut bias: Bias) -> InlayPoint { let mut cursor = self.transforms.cursor::>(()); cursor.seek(&point, Bias::Left); @@ -983,10 +1003,12 @@ impl InlaySnapshot { } } + #[ztracing::instrument(skip_all)] pub fn text_summary(&self) -> MBTextSummary { self.transforms.summary().output } + #[ztracing::instrument(skip_all)] pub fn text_summary_for_range(&self, range: Range) -> MBTextSummary { let mut summary = MBTextSummary::default(); @@ -1044,6 +1066,7 @@ impl InlaySnapshot { summary } + #[ztracing::instrument(skip_all)] pub fn row_infos(&self, row: u32) -> InlayBufferRows<'_> { let mut cursor = self.transforms.cursor::>(()); let inlay_point = InlayPoint::new(row, 0); @@ -1071,6 +1094,7 @@ impl InlaySnapshot { } } + #[ztracing::instrument(skip_all)] pub fn line_len(&self, row: u32) -> u32 { let line_start = self.to_offset(InlayPoint::new(row, 0)).0; let line_end = if row >= self.max_point().row() { @@ -1081,6 +1105,7 @@ impl InlaySnapshot { (line_end - line_start) as u32 } + #[ztracing::instrument(skip_all)] pub(crate) fn chunks<'a>( &'a self, range: Range, @@ -1115,12 +1140,14 @@ impl InlaySnapshot { } #[cfg(test)] + #[ztracing::instrument(skip_all)] pub fn text(&self) -> String { self.chunks(Default::default()..self.len(), false, Highlights::default()) .map(|chunk| chunk.chunk.text) .collect() } + #[ztracing::instrument(skip_all)] fn check_invariants(&self) { #[cfg(any(debug_assertions, feature = "test-support"))] { @@ -1147,6 +1174,7 @@ pub struct InlayPointCursor<'transforms> { } impl InlayPointCursor<'_> { + #[ztracing::instrument(skip_all)] pub fn map(&mut self, point: Point) -> InlayPoint { let cursor = &mut self.cursor; if cursor.did_seek() { diff --git a/crates/editor/src/display_map/invisibles.rs b/crates/editor/src/display_map/invisibles.rs index 5622a659b7..90bd54ab28 100644 --- a/crates/editor/src/display_map/invisibles.rs +++ b/crates/editor/src/display_map/invisibles.rs @@ -30,6 +30,7 @@ // ref: https://gist.github.com/ConradIrwin/f759e1fc29267143c4c7895aa495dca5?h=1 // ref: https://unicode.org/Public/emoji/13.0/emoji-test.txt // https://github.com/bits/UTF-8-Unicode-Test-Documents/blob/master/UTF-8_sequence_separated/utf8_sequence_0-0x10ffff_assigned_including-unprintable-asis.txt +#[ztracing::instrument(skip_all)] pub fn is_invisible(c: char) -> bool { if c <= '\u{1f}' { c != '\t' && c != '\n' && c != '\r' diff --git a/crates/editor/src/display_map/tab_map.rs b/crates/editor/src/display_map/tab_map.rs index 347d773215..4e768a4771 100644 --- a/crates/editor/src/display_map/tab_map.rs +++ b/crates/editor/src/display_map/tab_map.rs @@ -20,6 +20,7 @@ const MAX_TABS: NonZeroU32 = NonZeroU32::new(SPACES.len() as u32).unwrap(); pub struct TabMap(TabSnapshot); impl TabMap { + #[ztracing::instrument(skip_all)] pub fn new(fold_snapshot: FoldSnapshot, tab_size: NonZeroU32) -> (Self, TabSnapshot) { let snapshot = TabSnapshot { fold_snapshot, @@ -36,6 +37,7 @@ impl TabMap { self.0.clone() } + #[ztracing::instrument(skip_all)] pub fn sync( &mut self, fold_snapshot: FoldSnapshot, @@ -176,10 +178,12 @@ impl std::ops::Deref for TabSnapshot { } impl TabSnapshot { + #[ztracing::instrument(skip_all)] pub fn buffer_snapshot(&self) -> &MultiBufferSnapshot { &self.fold_snapshot.inlay_snapshot.buffer } + #[ztracing::instrument(skip_all)] pub fn line_len(&self, row: u32) -> u32 { let max_point = self.max_point(); if row < max_point.row() { @@ -191,10 +195,12 @@ impl TabSnapshot { } } + #[ztracing::instrument(skip_all)] pub fn text_summary(&self) -> TextSummary { self.text_summary_for_range(TabPoint::zero()..self.max_point()) } + #[ztracing::instrument(skip_all, fields(rows))] pub fn text_summary_for_range(&self, range: Range) -> TextSummary { let input_start = self.tab_point_to_fold_point(range.start, Bias::Left).0; let input_end = self.tab_point_to_fold_point(range.end, Bias::Right).0; @@ -234,6 +240,7 @@ impl TabSnapshot { } } + #[ztracing::instrument(skip_all)] pub(crate) fn chunks<'a>( &'a self, range: Range, @@ -276,11 +283,13 @@ impl TabSnapshot { } } + #[ztracing::instrument(skip_all)] pub fn rows(&self, row: u32) -> fold_map::FoldRows<'_> { self.fold_snapshot.row_infos(row) } #[cfg(test)] + #[ztracing::instrument(skip_all)] pub fn text(&self) -> String { self.chunks( TabPoint::zero()..self.max_point(), @@ -291,10 +300,12 @@ impl TabSnapshot { .collect() } + #[ztracing::instrument(skip_all)] pub fn max_point(&self) -> TabPoint { self.fold_point_to_tab_point(self.fold_snapshot.max_point()) } + #[ztracing::instrument(skip_all)] pub fn clip_point(&self, point: TabPoint, bias: Bias) -> TabPoint { self.fold_point_to_tab_point( self.fold_snapshot @@ -302,6 +313,7 @@ impl TabSnapshot { ) } + #[ztracing::instrument(skip_all)] pub fn fold_point_to_tab_point(&self, input: FoldPoint) -> TabPoint { let chunks = self.fold_snapshot.chunks_at(FoldPoint::new(input.row(), 0)); let tab_cursor = TabStopCursor::new(chunks); @@ -309,10 +321,12 @@ impl TabSnapshot { TabPoint::new(input.row(), expanded) } + #[ztracing::instrument(skip_all)] pub fn tab_point_cursor(&self) -> TabPointCursor<'_> { TabPointCursor { this: self } } + #[ztracing::instrument(skip_all)] pub fn tab_point_to_fold_point(&self, output: TabPoint, bias: Bias) -> (FoldPoint, u32, u32) { let chunks = self .fold_snapshot @@ -330,12 +344,14 @@ impl TabSnapshot { ) } + #[ztracing::instrument(skip_all)] pub fn point_to_tab_point(&self, point: Point, bias: Bias) -> TabPoint { let inlay_point = self.fold_snapshot.inlay_snapshot.to_inlay_point(point); let fold_point = self.fold_snapshot.to_fold_point(inlay_point, bias); self.fold_point_to_tab_point(fold_point) } + #[ztracing::instrument(skip_all)] pub fn tab_point_to_point(&self, point: TabPoint, bias: Bias) -> Point { let fold_point = self.tab_point_to_fold_point(point, bias).0; let inlay_point = fold_point.to_inlay_point(&self.fold_snapshot); @@ -344,6 +360,7 @@ impl TabSnapshot { .to_buffer_point(inlay_point) } + #[ztracing::instrument(skip_all)] fn expand_tabs<'a, I>(&self, mut cursor: TabStopCursor<'a, I>, column: u32) -> u32 where I: Iterator>, @@ -377,6 +394,7 @@ impl TabSnapshot { expanded_bytes + column.saturating_sub(collapsed_bytes) } + #[ztracing::instrument(skip_all)] fn collapse_tabs<'a, I>( &self, mut cursor: TabStopCursor<'a, I>, @@ -442,6 +460,7 @@ pub struct TabPointCursor<'this> { } impl TabPointCursor<'_> { + #[ztracing::instrument(skip_all)] pub fn map(&mut self, point: FoldPoint) -> TabPoint { self.this.fold_point_to_tab_point(point) } @@ -486,6 +505,7 @@ pub struct TextSummary { } impl<'a> From<&'a str> for TextSummary { + #[ztracing::instrument(skip_all)] fn from(text: &'a str) -> Self { let sum = text::TextSummary::from(text); @@ -500,6 +520,7 @@ impl<'a> From<&'a str> for TextSummary { } impl<'a> std::ops::AddAssign<&'a Self> for TextSummary { + #[ztracing::instrument(skip_all)] fn add_assign(&mut self, other: &'a Self) { let joined_chars = self.last_line_chars + other.first_line_chars; if joined_chars > self.longest_row_chars { @@ -541,6 +562,7 @@ pub struct TabChunks<'a> { } impl TabChunks<'_> { + #[ztracing::instrument(skip_all)] pub(crate) fn seek(&mut self, range: Range) { let (input_start, expanded_char_column, to_next_stop) = self .snapshot @@ -576,6 +598,7 @@ impl TabChunks<'_> { impl<'a> Iterator for TabChunks<'a> { type Item = Chunk<'a>; + #[ztracing::instrument(skip_all)] fn next(&mut self) -> Option { if self.chunk.text.is_empty() { if let Some(chunk) = self.fold_chunks.next() { @@ -1452,6 +1475,7 @@ impl<'a, I> TabStopCursor<'a, I> where I: Iterator>, { + #[ztracing::instrument(skip_all)] fn new(chunks: impl IntoIterator, IntoIter = I>) -> Self { Self { chunks: chunks.into_iter(), @@ -1461,6 +1485,7 @@ where } } + #[ztracing::instrument(skip_all)] fn bytes_until_next_char(&self) -> Option { self.current_chunk.as_ref().and_then(|(chunk, idx)| { let mut idx = *idx; @@ -1482,6 +1507,7 @@ where }) } + #[ztracing::instrument(skip_all)] fn is_char_boundary(&self) -> bool { self.current_chunk .as_ref() @@ -1489,6 +1515,7 @@ where } /// distance: length to move forward while searching for the next tab stop + #[ztracing::instrument(skip_all)] fn seek(&mut self, distance: u32) -> Option { if distance == 0 { return None; diff --git a/crates/editor/src/display_map/wrap_map.rs b/crates/editor/src/display_map/wrap_map.rs index 20ef939188..51d5324c83 100644 --- a/crates/editor/src/display_map/wrap_map.rs +++ b/crates/editor/src/display_map/wrap_map.rs @@ -86,6 +86,7 @@ pub struct WrapRows<'a> { } impl WrapRows<'_> { + #[ztracing::instrument(skip_all)] pub(crate) fn seek(&mut self, start_row: WrapRow) { self.transforms .seek(&WrapPoint::new(start_row, 0), Bias::Left); @@ -101,6 +102,7 @@ impl WrapRows<'_> { } impl WrapMap { + #[ztracing::instrument(skip_all)] pub fn new( tab_snapshot: TabSnapshot, font: Font, @@ -131,6 +133,7 @@ impl WrapMap { self.background_task.is_some() } + #[ztracing::instrument(skip_all)] pub fn sync( &mut self, tab_snapshot: TabSnapshot, @@ -150,6 +153,7 @@ impl WrapMap { (self.snapshot.clone(), mem::take(&mut self.edits_since_sync)) } + #[ztracing::instrument(skip_all)] pub fn set_font_with_size( &mut self, font: Font, @@ -167,6 +171,7 @@ impl WrapMap { } } + #[ztracing::instrument(skip_all)] pub fn set_wrap_width(&mut self, wrap_width: Option, cx: &mut Context) -> bool { if wrap_width == self.wrap_width { return false; @@ -177,6 +182,7 @@ impl WrapMap { true } + #[ztracing::instrument(skip_all)] fn rewrap(&mut self, cx: &mut Context) { self.background_task.take(); self.interpolated_edits.clear(); @@ -248,6 +254,7 @@ impl WrapMap { } } + #[ztracing::instrument(skip_all)] fn flush_edits(&mut self, cx: &mut Context) { if !self.snapshot.interpolated { let mut to_remove_len = 0; @@ -330,6 +337,7 @@ impl WrapMap { } impl WrapSnapshot { + #[ztracing::instrument(skip_all)] fn new(tab_snapshot: TabSnapshot) -> Self { let mut transforms = SumTree::default(); let extent = tab_snapshot.text_summary(); @@ -343,10 +351,12 @@ impl WrapSnapshot { } } + #[ztracing::instrument(skip_all)] pub fn buffer_snapshot(&self) -> &MultiBufferSnapshot { self.tab_snapshot.buffer_snapshot() } + #[ztracing::instrument(skip_all)] fn interpolate(&mut self, new_tab_snapshot: TabSnapshot, tab_edits: &[TabEdit]) -> WrapPatch { let mut new_transforms; if tab_edits.is_empty() { @@ -411,6 +421,7 @@ impl WrapSnapshot { old_snapshot.compute_edits(tab_edits, self) } + #[ztracing::instrument(skip_all)] async fn update( &mut self, new_tab_snapshot: TabSnapshot, @@ -570,6 +581,7 @@ impl WrapSnapshot { old_snapshot.compute_edits(tab_edits, self) } + #[ztracing::instrument(skip_all)] fn compute_edits(&self, tab_edits: &[TabEdit], new_snapshot: &WrapSnapshot) -> WrapPatch { let mut wrap_edits = Vec::with_capacity(tab_edits.len()); let mut old_cursor = self.transforms.cursor::(()); @@ -606,6 +618,7 @@ impl WrapSnapshot { Patch::new(wrap_edits) } + #[ztracing::instrument(skip_all)] pub(crate) fn chunks<'a>( &'a self, rows: Range, @@ -640,10 +653,12 @@ impl WrapSnapshot { } } + #[ztracing::instrument(skip_all)] pub fn max_point(&self) -> WrapPoint { WrapPoint(self.transforms.summary().output.lines) } + #[ztracing::instrument(skip_all)] pub fn line_len(&self, row: WrapRow) -> u32 { let (start, _, item) = self.transforms.find::, _>( (), @@ -664,6 +679,7 @@ impl WrapSnapshot { } } + #[ztracing::instrument(skip_all, fields(rows))] pub fn text_summary_for_range(&self, rows: Range) -> TextSummary { let mut summary = TextSummary::default(); @@ -725,6 +741,7 @@ impl WrapSnapshot { summary } + #[ztracing::instrument(skip_all)] pub fn soft_wrap_indent(&self, row: WrapRow) -> Option { let (.., item) = self.transforms.find::( (), @@ -740,10 +757,12 @@ impl WrapSnapshot { }) } + #[ztracing::instrument(skip_all)] pub fn longest_row(&self) -> u32 { self.transforms.summary().output.longest_row } + #[ztracing::instrument(skip_all)] pub fn row_infos(&self, start_row: WrapRow) -> WrapRows<'_> { let mut transforms = self .transforms @@ -766,6 +785,7 @@ impl WrapSnapshot { } } + #[ztracing::instrument(skip_all)] pub fn to_tab_point(&self, point: WrapPoint) -> TabPoint { let (start, _, item) = self.transforms @@ -777,15 +797,18 @@ impl WrapSnapshot { TabPoint(tab_point) } + #[ztracing::instrument(skip_all)] pub fn to_point(&self, point: WrapPoint, bias: Bias) -> Point { self.tab_snapshot .tab_point_to_point(self.to_tab_point(point), bias) } + #[ztracing::instrument(skip_all)] pub fn make_wrap_point(&self, point: Point, bias: Bias) -> WrapPoint { self.tab_point_to_wrap_point(self.tab_snapshot.point_to_tab_point(point, bias)) } + #[ztracing::instrument(skip_all)] pub fn tab_point_to_wrap_point(&self, point: TabPoint) -> WrapPoint { let (start, ..) = self.transforms @@ -793,6 +816,7 @@ impl WrapSnapshot { WrapPoint(start.1.0 + (point.0 - start.0.0)) } + #[ztracing::instrument(skip_all)] pub fn wrap_point_cursor(&self) -> WrapPointCursor<'_> { WrapPointCursor { cursor: self @@ -801,6 +825,7 @@ impl WrapSnapshot { } } + #[ztracing::instrument(skip_all)] pub fn clip_point(&self, mut point: WrapPoint, bias: Bias) -> WrapPoint { if bias == Bias::Left { let (start, _, item) = self @@ -815,6 +840,7 @@ impl WrapSnapshot { self.tab_point_to_wrap_point(self.tab_snapshot.clip_point(self.to_tab_point(point), bias)) } + #[ztracing::instrument(skip_all, fields(point, ret))] pub fn prev_row_boundary(&self, mut point: WrapPoint) -> WrapRow { if self.transforms.is_empty() { return WrapRow(0); @@ -841,6 +867,7 @@ impl WrapSnapshot { unreachable!() } + #[ztracing::instrument(skip_all)] pub fn next_row_boundary(&self, mut point: WrapPoint) -> Option { point.0 += Point::new(1, 0); @@ -860,11 +887,13 @@ impl WrapSnapshot { } #[cfg(test)] + #[ztracing::instrument(skip_all)] pub fn text(&self) -> String { self.text_chunks(WrapRow(0)).collect() } #[cfg(test)] + #[ztracing::instrument(skip_all)] pub fn text_chunks(&self, wrap_row: WrapRow) -> impl Iterator { self.chunks( wrap_row..self.max_point().row() + WrapRow(1), @@ -874,6 +903,7 @@ impl WrapSnapshot { .map(|h| h.text) } + #[ztracing::instrument(skip_all)] fn check_invariants(&self) { #[cfg(test)] { @@ -927,6 +957,7 @@ pub struct WrapPointCursor<'transforms> { } impl WrapPointCursor<'_> { + #[ztracing::instrument(skip_all)] pub fn map(&mut self, point: TabPoint) -> WrapPoint { let cursor = &mut self.cursor; if cursor.did_seek() { @@ -939,6 +970,7 @@ impl WrapPointCursor<'_> { } impl WrapChunks<'_> { + #[ztracing::instrument(skip_all)] pub(crate) fn seek(&mut self, rows: Range) { let output_start = WrapPoint::new(rows.start, 0); let output_end = WrapPoint::new(rows.end, 0); @@ -961,6 +993,7 @@ impl WrapChunks<'_> { impl<'a> Iterator for WrapChunks<'a> { type Item = Chunk<'a>; + #[ztracing::instrument(skip_all)] fn next(&mut self) -> Option { if self.output_position.row() >= self.max_output_row { return None; @@ -1033,6 +1066,7 @@ impl<'a> Iterator for WrapChunks<'a> { impl Iterator for WrapRows<'_> { type Item = RowInfo; + #[ztracing::instrument(skip_all)] fn next(&mut self) -> Option { if self.output_row > self.max_output_row { return None; @@ -1069,6 +1103,7 @@ impl Iterator for WrapRows<'_> { } impl Transform { + #[ztracing::instrument(skip_all)] fn isomorphic(summary: TextSummary) -> Self { #[cfg(test)] assert!(!summary.lines.is_zero()); @@ -1082,6 +1117,7 @@ impl Transform { } } + #[ztracing::instrument(skip_all)] fn wrap(indent: u32) -> Self { static WRAP_TEXT: LazyLock = LazyLock::new(|| { let mut wrap_text = String::new(); @@ -1134,6 +1170,7 @@ trait SumTreeExt { } impl SumTreeExt for SumTree { + #[ztracing::instrument(skip_all)] fn push_or_extend(&mut self, transform: Transform) { let mut transform = Some(transform); self.update_last( @@ -1197,6 +1234,7 @@ impl<'a> sum_tree::Dimension<'a, TransformSummary> for TabPoint { } impl sum_tree::SeekTarget<'_, TransformSummary, TransformSummary> for TabPoint { + #[ztracing::instrument(skip_all)] fn cmp(&self, cursor_location: &TransformSummary, _: ()) -> std::cmp::Ordering { Ord::cmp(&self.0, &cursor_location.input.lines) } diff --git a/crates/git_ui/Cargo.toml b/crates/git_ui/Cargo.toml index 5e96cd3529..beaf192b0e 100644 --- a/crates/git_ui/Cargo.toml +++ b/crates/git_ui/Cargo.toml @@ -13,7 +13,6 @@ name = "git_ui" path = "src/git_ui.rs" [features] -default = [] test-support = ["multi_buffer/test-support"] [dependencies] @@ -62,7 +61,8 @@ watch.workspace = true workspace.workspace = true zed_actions.workspace = true zeroize.workspace = true - +ztracing.workspace = true +tracing.workspace = true [target.'cfg(windows)'.dependencies] windows.workspace = true @@ -78,3 +78,6 @@ settings = { workspace = true, features = ["test-support"] } unindent.workspace = true workspace = { workspace = true, features = ["test-support"] } zlog.workspace = true + +[package.metadata.cargo-machete] +ignored = ["tracing"] diff --git a/crates/git_ui/src/project_diff.rs b/crates/git_ui/src/project_diff.rs index 0a8667ba6c..f211483c5e 100644 --- a/crates/git_ui/src/project_diff.rs +++ b/crates/git_ui/src/project_diff.rs @@ -46,6 +46,7 @@ use workspace::{ notifications::NotifyTaskExt, searchable::SearchableItemHandle, }; +use ztracing::instrument; actions!( git, @@ -469,6 +470,7 @@ impl ProjectDiff { } } + #[instrument(skip_all)] fn register_buffer( &mut self, path_key: PathKey, diff --git a/crates/multi_buffer/Cargo.toml b/crates/multi_buffer/Cargo.toml index 93747140c1..524c916682 100644 --- a/crates/multi_buffer/Cargo.toml +++ b/crates/multi_buffer/Cargo.toml @@ -42,6 +42,8 @@ sum_tree.workspace = true text.workspace = true theme.workspace = true tree-sitter.workspace = true +ztracing.workspace = true +tracing.workspace = true util.workspace = true [dev-dependencies] @@ -56,3 +58,6 @@ settings = { workspace = true, features = ["test-support"] } text = { workspace = true, features = ["test-support"] } util = { workspace = true, features = ["test-support"] } zlog.workspace = true + +[package.metadata.cargo-machete] +ignored = ["tracing"] diff --git a/crates/multi_buffer/src/multi_buffer.rs b/crates/multi_buffer/src/multi_buffer.rs index af36aaadf0..24cb55d2f5 100644 --- a/crates/multi_buffer/src/multi_buffer.rs +++ b/crates/multi_buffer/src/multi_buffer.rs @@ -57,6 +57,7 @@ use text::{ }; use theme::SyntaxTheme; use util::post_inc; +use ztracing::instrument; pub use self::path_key::PathKey; @@ -1671,6 +1672,7 @@ impl MultiBuffer { self.insert_excerpts_after(ExcerptId::max(), buffer, ranges, cx) } + #[instrument(skip_all)] fn merge_excerpt_ranges<'a>( expanded_ranges: impl IntoIterator> + 'a, ) -> (Vec>, Vec) { @@ -4483,6 +4485,7 @@ impl MultiBufferSnapshot { self.convert_dimension(point, text::BufferSnapshot::point_utf16_to_point) } + #[instrument(skip_all)] pub fn point_to_offset(&self, point: Point) -> MultiBufferOffset { self.convert_dimension(point, text::BufferSnapshot::point_to_offset) } @@ -4536,6 +4539,7 @@ impl MultiBufferSnapshot { } } + #[instrument(skip_all)] fn convert_dimension( &self, key: MBR1, @@ -6684,6 +6688,7 @@ where MBD: MultiBufferDimension + Ord + Sub + ops::AddAssign<::Output>, BD: TextDimension + AddAssign<::Output>, { + #[instrument(skip_all)] fn seek(&mut self, position: &MBD) { let position = OutputDimension(*position); self.cached_region.take(); diff --git a/crates/multi_buffer/src/path_key.rs b/crates/multi_buffer/src/path_key.rs index 1685e7a273..82bb902c23 100644 --- a/crates/multi_buffer/src/path_key.rs +++ b/crates/multi_buffer/src/path_key.rs @@ -1,435 +1,437 @@ -use std::{mem, ops::Range, sync::Arc}; - -use collections::HashSet; -use gpui::{App, AppContext, Context, Entity}; -use itertools::Itertools; -use language::{Buffer, BufferSnapshot}; -use rope::Point; -use text::{Bias, BufferId, OffsetRangeExt, locator::Locator}; -use util::{post_inc, rel_path::RelPath}; - -use crate::{ - Anchor, ExcerptId, ExcerptRange, ExpandExcerptDirection, MultiBuffer, build_excerpt_ranges, -}; - -#[derive(PartialEq, Eq, Ord, PartialOrd, Clone, Hash, Debug)] -pub struct PathKey { - // Used by the derived PartialOrd & Ord - pub sort_prefix: Option, - pub path: Arc, -} - -impl PathKey { - pub fn with_sort_prefix(sort_prefix: u64, path: Arc) -> Self { - Self { - sort_prefix: Some(sort_prefix), - path, - } - } - - pub fn for_buffer(buffer: &Entity, cx: &App) -> Self { - if let Some(file) = buffer.read(cx).file() { - Self::with_sort_prefix(file.worktree_id(cx).to_proto(), file.path().clone()) - } else { - Self { - sort_prefix: None, - path: RelPath::unix(&buffer.entity_id().to_string()) - .unwrap() - .into_arc(), - } - } - } -} - -impl MultiBuffer { - pub fn paths(&self) -> impl Iterator + '_ { - self.excerpts_by_path.keys().cloned() - } - - pub fn remove_excerpts_for_path(&mut self, path: PathKey, cx: &mut Context) { - if let Some(to_remove) = self.excerpts_by_path.remove(&path) { - self.remove_excerpts(to_remove, cx) - } - if let Some(follower) = &self.follower { - follower.update(cx, |follower, cx| { - follower.remove_excerpts_for_path(path, cx); - }); - } - } - - pub fn location_for_path(&self, path: &PathKey, cx: &App) -> Option { - let excerpt_id = self.excerpts_by_path.get(path)?.first()?; - let snapshot = self.read(cx); - let excerpt = snapshot.excerpt(*excerpt_id)?; - Some(Anchor::in_buffer(excerpt.id, excerpt.range.context.start)) - } - - pub fn excerpt_paths(&self) -> impl Iterator { - self.excerpts_by_path.keys() - } - - /// Sets excerpts, returns `true` if at least one new excerpt was added. - pub fn set_excerpts_for_path( - &mut self, - path: PathKey, - buffer: Entity, - ranges: impl IntoIterator>, - context_line_count: u32, - cx: &mut Context, - ) -> (Vec>, bool) { - let buffer_snapshot = buffer.read(cx).snapshot(); - let excerpt_ranges = build_excerpt_ranges(ranges, context_line_count, &buffer_snapshot); - - let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges); - self.set_merged_excerpt_ranges_for_path( - path, - buffer, - excerpt_ranges, - &buffer_snapshot, - new, - counts, - cx, - ) - } - - pub fn set_excerpt_ranges_for_path( - &mut self, - path: PathKey, - buffer: Entity, - buffer_snapshot: &BufferSnapshot, - excerpt_ranges: Vec>, - cx: &mut Context, - ) -> (Vec>, bool) { - let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges); - self.set_merged_excerpt_ranges_for_path( - path, - buffer, - excerpt_ranges, - buffer_snapshot, - new, - counts, - cx, - ) - } - - pub fn set_anchored_excerpts_for_path( - &self, - path_key: PathKey, - buffer: Entity, - ranges: Vec>, - context_line_count: u32, - cx: &Context, - ) -> impl Future>> + use<> { - let buffer_snapshot = buffer.read(cx).snapshot(); - let multi_buffer = cx.weak_entity(); - let mut app = cx.to_async(); - async move { - let snapshot = buffer_snapshot.clone(); - let (excerpt_ranges, new, counts) = app - .background_spawn(async move { - let ranges = ranges.into_iter().map(|range| range.to_point(&snapshot)); - let excerpt_ranges = - build_excerpt_ranges(ranges, context_line_count, &snapshot); - let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges); - (excerpt_ranges, new, counts) - }) - .await; - - multi_buffer - .update(&mut app, move |multi_buffer, cx| { - let (ranges, _) = multi_buffer.set_merged_excerpt_ranges_for_path( - path_key, - buffer, - excerpt_ranges, - &buffer_snapshot, - new, - counts, - cx, - ); - ranges - }) - .ok() - .unwrap_or_default() - } - } - - pub fn remove_excerpts_for_buffer(&mut self, buffer: BufferId, cx: &mut Context) { - self.remove_excerpts( - self.excerpts_for_buffer(buffer, cx) - .into_iter() - .map(|(excerpt, _)| excerpt), - cx, - ); - } - - pub(super) fn expand_excerpts_with_paths( - &mut self, - ids: impl IntoIterator, - line_count: u32, - direction: ExpandExcerptDirection, - cx: &mut Context, - ) { - let grouped = ids - .into_iter() - .chunk_by(|id| self.paths_by_excerpt.get(id).cloned()) - .into_iter() - .filter_map(|(k, v)| Some((k?, v.into_iter().collect::>()))) - .collect::>(); - let snapshot = self.snapshot(cx); - - for (path, ids) in grouped.into_iter() { - let Some(excerpt_ids) = self.excerpts_by_path.get(&path) else { - continue; - }; - - let ids_to_expand = HashSet::from_iter(ids); - let mut excerpt_id_ = None; - let expanded_ranges = excerpt_ids.iter().filter_map(|excerpt_id| { - let excerpt = snapshot.excerpt(*excerpt_id)?; - let excerpt_id = excerpt.id; - if excerpt_id_.is_none() { - excerpt_id_ = Some(excerpt_id); - } - - let mut context = excerpt.range.context.to_point(&excerpt.buffer); - if ids_to_expand.contains(&excerpt_id) { - match direction { - ExpandExcerptDirection::Up => { - context.start.row = context.start.row.saturating_sub(line_count); - context.start.column = 0; - } - ExpandExcerptDirection::Down => { - context.end.row = - (context.end.row + line_count).min(excerpt.buffer.max_point().row); - context.end.column = excerpt.buffer.line_len(context.end.row); - } - ExpandExcerptDirection::UpAndDown => { - context.start.row = context.start.row.saturating_sub(line_count); - context.start.column = 0; - context.end.row = - (context.end.row + line_count).min(excerpt.buffer.max_point().row); - context.end.column = excerpt.buffer.line_len(context.end.row); - } - } - } - - Some(ExcerptRange { - context, - primary: excerpt.range.primary.to_point(&excerpt.buffer), - }) - }); - let mut merged_ranges: Vec> = Vec::new(); - for range in expanded_ranges { - if let Some(last_range) = merged_ranges.last_mut() - && last_range.context.end >= range.context.start - { - last_range.context.end = range.context.end; - continue; - } - merged_ranges.push(range) - } - let Some(excerpt_id) = excerpt_id_ else { - continue; - }; - let Some(buffer_id) = &snapshot.buffer_id_for_excerpt(excerpt_id) else { - continue; - }; - - let Some(buffer) = self.buffers.get(buffer_id).map(|b| b.buffer.clone()) else { - continue; - }; - - let buffer_snapshot = buffer.read(cx).snapshot(); - self.update_path_excerpts(path.clone(), buffer, &buffer_snapshot, merged_ranges, cx); - } - } - - /// Sets excerpts, returns `true` if at least one new excerpt was added. - fn set_merged_excerpt_ranges_for_path( - &mut self, - path: PathKey, - buffer: Entity, - ranges: Vec>, - buffer_snapshot: &BufferSnapshot, - new: Vec>, - counts: Vec, - cx: &mut Context, - ) -> (Vec>, bool) { - let (excerpt_ids, added_a_new_excerpt) = - self.update_path_excerpts(path, buffer, buffer_snapshot, new, cx); - - let mut result = Vec::new(); - let mut ranges = ranges.into_iter(); - for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(counts.into_iter()) { - for range in ranges.by_ref().take(range_count) { - let range = Anchor::range_in_buffer( - excerpt_id, - buffer_snapshot.anchor_before(&range.primary.start) - ..buffer_snapshot.anchor_after(&range.primary.end), - ); - result.push(range) - } - } - (result, added_a_new_excerpt) - } - - fn update_path_excerpts( - &mut self, - path: PathKey, - buffer: Entity, - buffer_snapshot: &BufferSnapshot, - new: Vec>, - cx: &mut Context, - ) -> (Vec, bool) { - let mut insert_after = self - .excerpts_by_path - .range(..path.clone()) - .next_back() - .and_then(|(_, value)| value.last().copied()) - .unwrap_or(ExcerptId::min()); - - let existing = self - .excerpts_by_path - .get(&path) - .cloned() - .unwrap_or_default(); - let mut new_iter = new.into_iter().peekable(); - let mut existing_iter = existing.into_iter().peekable(); - - let mut excerpt_ids = Vec::new(); - let mut to_remove = Vec::new(); - let mut to_insert: Vec<(ExcerptId, ExcerptRange)> = Vec::new(); - let mut added_a_new_excerpt = false; - let snapshot = self.snapshot(cx); - - let mut next_excerpt_id = - // is this right? What if we remove the last excerpt, then we might reallocate with a wrong mapping? - if let Some(last_entry) = self.snapshot.borrow().excerpt_ids.last() { - last_entry.id.0 + 1 - } else { - 1 - }; - - let mut next_excerpt_id = move || ExcerptId(post_inc(&mut next_excerpt_id)); - - let mut excerpts_cursor = snapshot.excerpts.cursor::>(()); - excerpts_cursor.next(); - - loop { - let existing = if let Some(&existing_id) = existing_iter.peek() { - let locator = snapshot.excerpt_locator_for_id(existing_id); - excerpts_cursor.seek_forward(&Some(locator), Bias::Left); - if let Some(excerpt) = excerpts_cursor.item() { - if excerpt.buffer_id != buffer_snapshot.remote_id() { - to_remove.push(existing_id); - existing_iter.next(); - continue; - } - Some((existing_id, excerpt.range.context.to_point(buffer_snapshot))) - } else { - None - } - } else { - None - }; - - let new = new_iter.peek(); - if let Some((last_id, last)) = to_insert.last_mut() { - if let Some(new) = new - && last.context.end >= new.context.start - { - last.context.end = last.context.end.max(new.context.end); - excerpt_ids.push(*last_id); - new_iter.next(); - continue; - } - if let Some((existing_id, existing_range)) = &existing - && last.context.end >= existing_range.start - { - last.context.end = last.context.end.max(existing_range.end); - to_remove.push(*existing_id); - self.snapshot - .get_mut() - .replaced_excerpts - .insert(*existing_id, *last_id); - existing_iter.next(); - continue; - } - } - - match (new, existing) { - (None, None) => break, - (None, Some((existing_id, _))) => { - existing_iter.next(); - to_remove.push(existing_id); - continue; - } - (Some(_), None) => { - added_a_new_excerpt = true; - let new_id = next_excerpt_id(); - excerpt_ids.push(new_id); - to_insert.push((new_id, new_iter.next().unwrap())); - continue; - } - (Some(new), Some((_, existing_range))) => { - if existing_range.end < new.context.start { - let existing_id = existing_iter.next().unwrap(); - to_remove.push(existing_id); - continue; - } else if existing_range.start > new.context.end { - let new_id = next_excerpt_id(); - excerpt_ids.push(new_id); - to_insert.push((new_id, new_iter.next().unwrap())); - continue; - } - - if existing_range.start == new.context.start - && existing_range.end == new.context.end - { - self.insert_excerpts_with_ids_after( - insert_after, - buffer.clone(), - mem::take(&mut to_insert), - cx, - ); - insert_after = existing_iter.next().unwrap(); - excerpt_ids.push(insert_after); - new_iter.next(); - } else { - let existing_id = existing_iter.next().unwrap(); - let new_id = next_excerpt_id(); - self.snapshot - .get_mut() - .replaced_excerpts - .insert(existing_id, new_id); - to_remove.push(existing_id); - let mut range = new_iter.next().unwrap(); - range.context.start = range.context.start.min(existing_range.start); - range.context.end = range.context.end.max(existing_range.end); - excerpt_ids.push(new_id); - to_insert.push((new_id, range)); - } - } - }; - } - - self.insert_excerpts_with_ids_after(insert_after, buffer, to_insert, cx); - // todo(lw): There is a logic bug somewhere that causes the to_remove vector to be not ordered correctly - to_remove.sort_by_cached_key(|&id| snapshot.excerpt_locator_for_id(id)); - self.remove_excerpts(to_remove, cx); - - if excerpt_ids.is_empty() { - self.excerpts_by_path.remove(&path); - } else { - for excerpt_id in &excerpt_ids { - self.paths_by_excerpt.insert(*excerpt_id, path.clone()); - } - let snapshot = &*self.snapshot.get_mut(); - let mut excerpt_ids: Vec<_> = excerpt_ids.iter().dedup().cloned().collect(); - excerpt_ids.sort_by_cached_key(|&id| snapshot.excerpt_locator_for_id(id)); - self.excerpts_by_path.insert(path, excerpt_ids); - } - - (excerpt_ids, added_a_new_excerpt) - } -} +use std::{mem, ops::Range, sync::Arc}; + +use collections::HashSet; +use gpui::{App, AppContext, Context, Entity}; +use itertools::Itertools; +use language::{Buffer, BufferSnapshot}; +use rope::Point; +use text::{Bias, BufferId, OffsetRangeExt, locator::Locator}; +use util::{post_inc, rel_path::RelPath}; +use ztracing::instrument; + +use crate::{ + Anchor, ExcerptId, ExcerptRange, ExpandExcerptDirection, MultiBuffer, build_excerpt_ranges, +}; + +#[derive(PartialEq, Eq, Ord, PartialOrd, Clone, Hash, Debug)] +pub struct PathKey { + // Used by the derived PartialOrd & Ord + pub sort_prefix: Option, + pub path: Arc, +} + +impl PathKey { + pub fn with_sort_prefix(sort_prefix: u64, path: Arc) -> Self { + Self { + sort_prefix: Some(sort_prefix), + path, + } + } + + pub fn for_buffer(buffer: &Entity, cx: &App) -> Self { + if let Some(file) = buffer.read(cx).file() { + Self::with_sort_prefix(file.worktree_id(cx).to_proto(), file.path().clone()) + } else { + Self { + sort_prefix: None, + path: RelPath::unix(&buffer.entity_id().to_string()) + .unwrap() + .into_arc(), + } + } + } +} + +impl MultiBuffer { + pub fn paths(&self) -> impl Iterator + '_ { + self.excerpts_by_path.keys().cloned() + } + + pub fn remove_excerpts_for_path(&mut self, path: PathKey, cx: &mut Context) { + if let Some(to_remove) = self.excerpts_by_path.remove(&path) { + self.remove_excerpts(to_remove, cx) + } + if let Some(follower) = &self.follower { + follower.update(cx, |follower, cx| { + follower.remove_excerpts_for_path(path, cx); + }); + } + } + + pub fn location_for_path(&self, path: &PathKey, cx: &App) -> Option { + let excerpt_id = self.excerpts_by_path.get(path)?.first()?; + let snapshot = self.read(cx); + let excerpt = snapshot.excerpt(*excerpt_id)?; + Some(Anchor::in_buffer(excerpt.id, excerpt.range.context.start)) + } + + pub fn excerpt_paths(&self) -> impl Iterator { + self.excerpts_by_path.keys() + } + + /// Sets excerpts, returns `true` if at least one new excerpt was added. + #[instrument(skip_all)] + pub fn set_excerpts_for_path( + &mut self, + path: PathKey, + buffer: Entity, + ranges: impl IntoIterator>, + context_line_count: u32, + cx: &mut Context, + ) -> (Vec>, bool) { + let buffer_snapshot = buffer.read(cx).snapshot(); + let excerpt_ranges = build_excerpt_ranges(ranges, context_line_count, &buffer_snapshot); + + let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges); + self.set_merged_excerpt_ranges_for_path( + path, + buffer, + excerpt_ranges, + &buffer_snapshot, + new, + counts, + cx, + ) + } + + pub fn set_excerpt_ranges_for_path( + &mut self, + path: PathKey, + buffer: Entity, + buffer_snapshot: &BufferSnapshot, + excerpt_ranges: Vec>, + cx: &mut Context, + ) -> (Vec>, bool) { + let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges); + self.set_merged_excerpt_ranges_for_path( + path, + buffer, + excerpt_ranges, + buffer_snapshot, + new, + counts, + cx, + ) + } + + pub fn set_anchored_excerpts_for_path( + &self, + path_key: PathKey, + buffer: Entity, + ranges: Vec>, + context_line_count: u32, + cx: &Context, + ) -> impl Future>> + use<> { + let buffer_snapshot = buffer.read(cx).snapshot(); + let multi_buffer = cx.weak_entity(); + let mut app = cx.to_async(); + async move { + let snapshot = buffer_snapshot.clone(); + let (excerpt_ranges, new, counts) = app + .background_spawn(async move { + let ranges = ranges.into_iter().map(|range| range.to_point(&snapshot)); + let excerpt_ranges = + build_excerpt_ranges(ranges, context_line_count, &snapshot); + let (new, counts) = Self::merge_excerpt_ranges(&excerpt_ranges); + (excerpt_ranges, new, counts) + }) + .await; + + multi_buffer + .update(&mut app, move |multi_buffer, cx| { + let (ranges, _) = multi_buffer.set_merged_excerpt_ranges_for_path( + path_key, + buffer, + excerpt_ranges, + &buffer_snapshot, + new, + counts, + cx, + ); + ranges + }) + .ok() + .unwrap_or_default() + } + } + + pub fn remove_excerpts_for_buffer(&mut self, buffer: BufferId, cx: &mut Context) { + self.remove_excerpts( + self.excerpts_for_buffer(buffer, cx) + .into_iter() + .map(|(excerpt, _)| excerpt), + cx, + ); + } + + pub(super) fn expand_excerpts_with_paths( + &mut self, + ids: impl IntoIterator, + line_count: u32, + direction: ExpandExcerptDirection, + cx: &mut Context, + ) { + let grouped = ids + .into_iter() + .chunk_by(|id| self.paths_by_excerpt.get(id).cloned()) + .into_iter() + .filter_map(|(k, v)| Some((k?, v.into_iter().collect::>()))) + .collect::>(); + let snapshot = self.snapshot(cx); + + for (path, ids) in grouped.into_iter() { + let Some(excerpt_ids) = self.excerpts_by_path.get(&path) else { + continue; + }; + + let ids_to_expand = HashSet::from_iter(ids); + let mut excerpt_id_ = None; + let expanded_ranges = excerpt_ids.iter().filter_map(|excerpt_id| { + let excerpt = snapshot.excerpt(*excerpt_id)?; + let excerpt_id = excerpt.id; + if excerpt_id_.is_none() { + excerpt_id_ = Some(excerpt_id); + } + + let mut context = excerpt.range.context.to_point(&excerpt.buffer); + if ids_to_expand.contains(&excerpt_id) { + match direction { + ExpandExcerptDirection::Up => { + context.start.row = context.start.row.saturating_sub(line_count); + context.start.column = 0; + } + ExpandExcerptDirection::Down => { + context.end.row = + (context.end.row + line_count).min(excerpt.buffer.max_point().row); + context.end.column = excerpt.buffer.line_len(context.end.row); + } + ExpandExcerptDirection::UpAndDown => { + context.start.row = context.start.row.saturating_sub(line_count); + context.start.column = 0; + context.end.row = + (context.end.row + line_count).min(excerpt.buffer.max_point().row); + context.end.column = excerpt.buffer.line_len(context.end.row); + } + } + } + + Some(ExcerptRange { + context, + primary: excerpt.range.primary.to_point(&excerpt.buffer), + }) + }); + let mut merged_ranges: Vec> = Vec::new(); + for range in expanded_ranges { + if let Some(last_range) = merged_ranges.last_mut() + && last_range.context.end >= range.context.start + { + last_range.context.end = range.context.end; + continue; + } + merged_ranges.push(range) + } + let Some(excerpt_id) = excerpt_id_ else { + continue; + }; + let Some(buffer_id) = &snapshot.buffer_id_for_excerpt(excerpt_id) else { + continue; + }; + + let Some(buffer) = self.buffers.get(buffer_id).map(|b| b.buffer.clone()) else { + continue; + }; + + let buffer_snapshot = buffer.read(cx).snapshot(); + self.update_path_excerpts(path.clone(), buffer, &buffer_snapshot, merged_ranges, cx); + } + } + + /// Sets excerpts, returns `true` if at least one new excerpt was added. + fn set_merged_excerpt_ranges_for_path( + &mut self, + path: PathKey, + buffer: Entity, + ranges: Vec>, + buffer_snapshot: &BufferSnapshot, + new: Vec>, + counts: Vec, + cx: &mut Context, + ) -> (Vec>, bool) { + let (excerpt_ids, added_a_new_excerpt) = + self.update_path_excerpts(path, buffer, buffer_snapshot, new, cx); + + let mut result = Vec::new(); + let mut ranges = ranges.into_iter(); + for (excerpt_id, range_count) in excerpt_ids.into_iter().zip(counts.into_iter()) { + for range in ranges.by_ref().take(range_count) { + let range = Anchor::range_in_buffer( + excerpt_id, + buffer_snapshot.anchor_before(&range.primary.start) + ..buffer_snapshot.anchor_after(&range.primary.end), + ); + result.push(range) + } + } + (result, added_a_new_excerpt) + } + + fn update_path_excerpts( + &mut self, + path: PathKey, + buffer: Entity, + buffer_snapshot: &BufferSnapshot, + new: Vec>, + cx: &mut Context, + ) -> (Vec, bool) { + let mut insert_after = self + .excerpts_by_path + .range(..path.clone()) + .next_back() + .and_then(|(_, value)| value.last().copied()) + .unwrap_or(ExcerptId::min()); + + let existing = self + .excerpts_by_path + .get(&path) + .cloned() + .unwrap_or_default(); + let mut new_iter = new.into_iter().peekable(); + let mut existing_iter = existing.into_iter().peekable(); + + let mut excerpt_ids = Vec::new(); + let mut to_remove = Vec::new(); + let mut to_insert: Vec<(ExcerptId, ExcerptRange)> = Vec::new(); + let mut added_a_new_excerpt = false; + let snapshot = self.snapshot(cx); + + let mut next_excerpt_id = + // is this right? What if we remove the last excerpt, then we might reallocate with a wrong mapping? + if let Some(last_entry) = self.snapshot.borrow().excerpt_ids.last() { + last_entry.id.0 + 1 + } else { + 1 + }; + + let mut next_excerpt_id = move || ExcerptId(post_inc(&mut next_excerpt_id)); + + let mut excerpts_cursor = snapshot.excerpts.cursor::>(()); + excerpts_cursor.next(); + + loop { + let existing = if let Some(&existing_id) = existing_iter.peek() { + let locator = snapshot.excerpt_locator_for_id(existing_id); + excerpts_cursor.seek_forward(&Some(locator), Bias::Left); + if let Some(excerpt) = excerpts_cursor.item() { + if excerpt.buffer_id != buffer_snapshot.remote_id() { + to_remove.push(existing_id); + existing_iter.next(); + continue; + } + Some((existing_id, excerpt.range.context.to_point(buffer_snapshot))) + } else { + None + } + } else { + None + }; + + let new = new_iter.peek(); + if let Some((last_id, last)) = to_insert.last_mut() { + if let Some(new) = new + && last.context.end >= new.context.start + { + last.context.end = last.context.end.max(new.context.end); + excerpt_ids.push(*last_id); + new_iter.next(); + continue; + } + if let Some((existing_id, existing_range)) = &existing + && last.context.end >= existing_range.start + { + last.context.end = last.context.end.max(existing_range.end); + to_remove.push(*existing_id); + self.snapshot + .get_mut() + .replaced_excerpts + .insert(*existing_id, *last_id); + existing_iter.next(); + continue; + } + } + + match (new, existing) { + (None, None) => break, + (None, Some((existing_id, _))) => { + existing_iter.next(); + to_remove.push(existing_id); + continue; + } + (Some(_), None) => { + added_a_new_excerpt = true; + let new_id = next_excerpt_id(); + excerpt_ids.push(new_id); + to_insert.push((new_id, new_iter.next().unwrap())); + continue; + } + (Some(new), Some((_, existing_range))) => { + if existing_range.end < new.context.start { + let existing_id = existing_iter.next().unwrap(); + to_remove.push(existing_id); + continue; + } else if existing_range.start > new.context.end { + let new_id = next_excerpt_id(); + excerpt_ids.push(new_id); + to_insert.push((new_id, new_iter.next().unwrap())); + continue; + } + + if existing_range.start == new.context.start + && existing_range.end == new.context.end + { + self.insert_excerpts_with_ids_after( + insert_after, + buffer.clone(), + mem::take(&mut to_insert), + cx, + ); + insert_after = existing_iter.next().unwrap(); + excerpt_ids.push(insert_after); + new_iter.next(); + } else { + let existing_id = existing_iter.next().unwrap(); + let new_id = next_excerpt_id(); + self.snapshot + .get_mut() + .replaced_excerpts + .insert(existing_id, new_id); + to_remove.push(existing_id); + let mut range = new_iter.next().unwrap(); + range.context.start = range.context.start.min(existing_range.start); + range.context.end = range.context.end.max(existing_range.end); + excerpt_ids.push(new_id); + to_insert.push((new_id, range)); + } + } + }; + } + + self.insert_excerpts_with_ids_after(insert_after, buffer, to_insert, cx); + // todo(lw): There is a logic bug somewhere that causes the to_remove vector to be not ordered correctly + to_remove.sort_by_cached_key(|&id| snapshot.excerpt_locator_for_id(id)); + self.remove_excerpts(to_remove, cx); + + if excerpt_ids.is_empty() { + self.excerpts_by_path.remove(&path); + } else { + for excerpt_id in &excerpt_ids { + self.paths_by_excerpt.insert(*excerpt_id, path.clone()); + } + let snapshot = &*self.snapshot.get_mut(); + let mut excerpt_ids: Vec<_> = excerpt_ids.iter().dedup().cloned().collect(); + excerpt_ids.sort_by_cached_key(|&id| snapshot.excerpt_locator_for_id(id)); + self.excerpts_by_path.insert(path, excerpt_ids); + } + + (excerpt_ids, added_a_new_excerpt) + } +} diff --git a/crates/project/Cargo.toml b/crates/project/Cargo.toml index a33efb9896..9e2789fc10 100644 --- a/crates/project/Cargo.toml +++ b/crates/project/Cargo.toml @@ -91,6 +91,8 @@ which.workspace = true worktree.workspace = true zeroize.workspace = true zlog.workspace = true +ztracing.workspace = true +tracing.workspace = true [dev-dependencies] client = { workspace = true, features = ["test-support"] } @@ -113,3 +115,6 @@ snippet_provider = { workspace = true, features = ["test-support"] } unindent.workspace = true util = { workspace = true, features = ["test-support"] } worktree = { workspace = true, features = ["test-support"] } + +[package.metadata.cargo-machete] +ignored = ["tracing"] diff --git a/crates/project/src/git_store/branch_diff.rs b/crates/project/src/git_store/branch_diff.rs index 5065eafe4e..dd0026961e 100644 --- a/crates/project/src/git_store/branch_diff.rs +++ b/crates/project/src/git_store/branch_diff.rs @@ -14,6 +14,7 @@ use gpui::{ use language::Buffer; use text::BufferId; use util::ResultExt; +use ztracing::instrument; use crate::{ Project, @@ -254,6 +255,7 @@ impl BranchDiff { self.repo.as_ref() } + #[instrument(skip_all)] pub fn load_buffers(&mut self, cx: &mut Context) -> Vec { let mut output = Vec::default(); let Some(repo) = self.repo.clone() else { @@ -318,6 +320,7 @@ impl BranchDiff { output } + #[instrument(skip_all)] fn load_buffer( branch_diff: Option, project_path: crate::ProjectPath, diff --git a/crates/rope/Cargo.toml b/crates/rope/Cargo.toml index 4107c2e012..9f0fc2be8a 100644 --- a/crates/rope/Cargo.toml +++ b/crates/rope/Cargo.toml @@ -18,6 +18,8 @@ rayon.workspace = true sum_tree.workspace = true unicode-segmentation.workspace = true util.workspace = true +ztracing.workspace = true +tracing.workspace = true [dev-dependencies] ctor.workspace = true @@ -30,3 +32,6 @@ zlog.workspace = true [[bench]] name = "rope_benchmark" harness = false + +[package.metadata.cargo-machete] +ignored = ["tracing"] diff --git a/crates/rope/src/rope.rs b/crates/rope/src/rope.rs index 2d3c811e17..50f9ba044d 100644 --- a/crates/rope/src/rope.rs +++ b/crates/rope/src/rope.rs @@ -12,6 +12,7 @@ use std::{ str, }; use sum_tree::{Bias, Dimension, Dimensions, SumTree}; +use ztracing::instrument; pub use chunk::{Chunk, ChunkSlice}; pub use offset_utf16::OffsetUtf16; @@ -428,6 +429,7 @@ impl Rope { }) } + #[instrument(skip_all)] pub fn point_to_offset(&self, point: Point) -> usize { if point >= self.summary().lines { return self.summary().len; diff --git a/crates/sum_tree/Cargo.toml b/crates/sum_tree/Cargo.toml index 81916c8422..3e06ede162 100644 --- a/crates/sum_tree/Cargo.toml +++ b/crates/sum_tree/Cargo.toml @@ -17,8 +17,13 @@ doctest = false arrayvec = "0.7.1" rayon.workspace = true log.workspace = true +ztracing.workspace = true +tracing.workspace = true [dev-dependencies] ctor.workspace = true rand.workspace = true zlog.workspace = true + +[package.metadata.cargo-machete] +ignored = ["tracing"] diff --git a/crates/sum_tree/src/cursor.rs b/crates/sum_tree/src/cursor.rs index 0ca89d16db..589ae96a2a 100644 --- a/crates/sum_tree/src/cursor.rs +++ b/crates/sum_tree/src/cursor.rs @@ -1,6 +1,7 @@ use super::*; use arrayvec::ArrayVec; use std::{cmp::Ordering, mem, sync::Arc}; +use ztracing::instrument; #[derive(Clone)] struct StackEntry<'a, T: Item, D> { @@ -211,6 +212,7 @@ where } #[track_caller] + #[instrument(skip_all)] pub fn prev(&mut self) { self.search_backward(|_| true) } @@ -394,6 +396,7 @@ where { /// Returns whether we found the item you were seeking for. #[track_caller] + #[instrument(skip_all)] pub fn seek(&mut self, pos: &Target, bias: Bias) -> bool where Target: SeekTarget<'a, T::Summary, D>, @@ -408,6 +411,7 @@ where /// /// If we did not seek before, use seek instead in that case. #[track_caller] + #[instrument(skip_all)] pub fn seek_forward(&mut self, pos: &Target, bias: Bias) -> bool where Target: SeekTarget<'a, T::Summary, D>, @@ -449,6 +453,7 @@ where /// Returns whether we found the item you were seeking for. #[track_caller] + #[instrument(skip_all)] fn seek_internal( &mut self, target: &dyn SeekTarget<'a, T::Summary, D>, diff --git a/crates/sum_tree/src/sum_tree.rs b/crates/sum_tree/src/sum_tree.rs index da700201f5..bfc4587969 100644 --- a/crates/sum_tree/src/sum_tree.rs +++ b/crates/sum_tree/src/sum_tree.rs @@ -8,6 +8,7 @@ use std::marker::PhantomData; use std::mem; use std::{cmp::Ordering, fmt, iter::FromIterator, sync::Arc}; pub use tree_map::{MapSeekTarget, TreeMap, TreeSet}; +use ztracing::instrument; #[cfg(test)] pub const TREE_BASE: usize = 2; @@ -379,6 +380,7 @@ impl SumTree { /// A more efficient version of `Cursor::new()` + `Cursor::seek()` + `Cursor::item()`. /// /// Only returns the item that exactly has the target match. + #[instrument(skip_all)] pub fn find_exact<'a, 'slf, D, Target>( &'slf self, cx: ::Context<'a>, @@ -404,6 +406,7 @@ impl SumTree { } /// A more efficient version of `Cursor::new()` + `Cursor::seek()` + `Cursor::item()` + #[instrument(skip_all)] pub fn find<'a, 'slf, D, Target>( &'slf self, cx: ::Context<'a>, diff --git a/crates/zed/Cargo.toml b/crates/zed/Cargo.toml index 6ee7d0a4ea..e304ad7f5c 100644 --- a/crates/zed/Cargo.toml +++ b/crates/zed/Cargo.toml @@ -144,6 +144,8 @@ theme_extension.workspace = true theme_selector.workspace = true time.workspace = true title_bar.workspace = true +ztracing.workspace = true +tracing.workspace = true toolchain_selector.workspace = true ui.workspace = true ui_input.workspace = true @@ -223,4 +225,4 @@ osx_info_plist_exts = ["resources/info/*"] osx_url_schemes = ["zed"] [package.metadata.cargo-machete] -ignored = ["profiling", "zstd"] +ignored = ["profiling", "zstd", "tracing"] diff --git a/crates/zed/src/main.rs b/crates/zed/src/main.rs index 10f599e876..7751e6cb01 100644 --- a/crates/zed/src/main.rs +++ b/crates/zed/src/main.rs @@ -162,10 +162,11 @@ fn fail_to_open_window(e: anyhow::Error, _cx: &mut App) { .detach(); } } - pub static STARTUP_TIME: OnceLock = OnceLock::new(); pub fn main() { + ztracing::init(); + STARTUP_TIME.get_or_init(|| Instant::now()); #[cfg(unix)] diff --git a/crates/ztracing/Cargo.toml b/crates/ztracing/Cargo.toml new file mode 100644 index 0000000000..fbc9dc032d --- /dev/null +++ b/crates/ztracing/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "ztracing" +version = "0.1.0" +edition.workspace = true +publish.workspace = true +license = "GPL-3.0-or-later" + +[lints] +workspace = true + +[dependencies] +tracing.workspace = true + +tracing-subscriber = "0.3.22" +tracing-tracy = { workspace = true, features = ["enable", "ondemand"] } + +ztracing_macro.workspace = true diff --git a/crates/ztracing/LICENSE-AGPL b/crates/ztracing/LICENSE-AGPL new file mode 120000 index 0000000000..5f5cf25dc4 --- /dev/null +++ b/crates/ztracing/LICENSE-AGPL @@ -0,0 +1 @@ +../../LICENSE-AGPL \ No newline at end of file diff --git a/crates/ztracing/LICENSE-APACHE b/crates/ztracing/LICENSE-APACHE new file mode 120000 index 0000000000..1cd601d0a3 --- /dev/null +++ b/crates/ztracing/LICENSE-APACHE @@ -0,0 +1 @@ +../../LICENSE-APACHE \ No newline at end of file diff --git a/crates/ztracing/LICENSE-GPL b/crates/ztracing/LICENSE-GPL new file mode 120000 index 0000000000..89e542f750 --- /dev/null +++ b/crates/ztracing/LICENSE-GPL @@ -0,0 +1 @@ +../../LICENSE-GPL \ No newline at end of file diff --git a/crates/ztracing/build.rs b/crates/ztracing/build.rs new file mode 100644 index 0000000000..dc0d0ad704 --- /dev/null +++ b/crates/ztracing/build.rs @@ -0,0 +1,9 @@ +use std::env; + +fn main() { + if env::var_os("ZTRACING").is_some() { + println!(r"cargo::rustc-cfg=ztracing"); + } + println!("cargo::rerun-if-changed=build.rs"); + println!("cargo::rerun-if-env-changed=ZTRACING"); +} diff --git a/crates/ztracing/src/lib.rs b/crates/ztracing/src/lib.rs new file mode 100644 index 0000000000..1ab687a2f4 --- /dev/null +++ b/crates/ztracing/src/lib.rs @@ -0,0 +1,16 @@ +#[cfg(ztracing)] +pub use tracing::instrument; +#[cfg(not(ztracing))] +pub use ztracing_macro::instrument; + +#[cfg(ztracing)] +pub fn init() { + use tracing_subscriber::prelude::*; + tracing::subscriber::set_global_default( + tracing_subscriber::registry().with(tracing_tracy::TracyLayer::default()), + ) + .expect("setup tracy layer"); +} + +#[cfg(not(ztracing))] +pub fn init() {} diff --git a/crates/ztracing_macro/Cargo.toml b/crates/ztracing_macro/Cargo.toml new file mode 100644 index 0000000000..dbd7adce5f --- /dev/null +++ b/crates/ztracing_macro/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "ztracing_macro" +version = "0.1.0" +edition.workspace = true +publish.workspace = true +license = "GPL-3.0-or-later" + +[lib] +proc-macro = true + +[dependencies] diff --git a/crates/ztracing_macro/LICENSE-AGPL b/crates/ztracing_macro/LICENSE-AGPL new file mode 120000 index 0000000000..5f5cf25dc4 --- /dev/null +++ b/crates/ztracing_macro/LICENSE-AGPL @@ -0,0 +1 @@ +../../LICENSE-AGPL \ No newline at end of file diff --git a/crates/ztracing_macro/LICENSE-APACHE b/crates/ztracing_macro/LICENSE-APACHE new file mode 120000 index 0000000000..1cd601d0a3 --- /dev/null +++ b/crates/ztracing_macro/LICENSE-APACHE @@ -0,0 +1 @@ +../../LICENSE-APACHE \ No newline at end of file diff --git a/crates/ztracing_macro/LICENSE-GPL b/crates/ztracing_macro/LICENSE-GPL new file mode 120000 index 0000000000..89e542f750 --- /dev/null +++ b/crates/ztracing_macro/LICENSE-GPL @@ -0,0 +1 @@ +../../LICENSE-GPL \ No newline at end of file diff --git a/crates/ztracing_macro/src/lib.rs b/crates/ztracing_macro/src/lib.rs new file mode 100644 index 0000000000..d9b073ed13 --- /dev/null +++ b/crates/ztracing_macro/src/lib.rs @@ -0,0 +1,7 @@ +#[proc_macro_attribute] +pub fn instrument( + _attr: proc_macro::TokenStream, + item: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + item +} diff --git a/docs/src/performance.md b/docs/src/performance.md index a04d7c5c34..4adc38f5ee 100644 --- a/docs/src/performance.md +++ b/docs/src/performance.md @@ -1,6 +1,6 @@ How to use our internal tools to profile and keep Zed fast. -# Flamechart/CPU profiling +# Rough quick CPU profiling (Flamechart) See what the CPU spends the most time on. Strongly recommend you use [samply](https://github.com/mstange/samply). It opens an interactive profile in @@ -12,6 +12,46 @@ The profile.json does not contain any symbols. Firefox profiler can add the loca image +# In depth CPU profiling (Tracing) + +See how long each annotated function call took and its arguments (if +configured). + +Annotate any function you need appear in the profile with instrument. For more +details see +[tracing-instrument](https://docs.rs/tracing/latest/tracing/attr.instrument.html): + +```rust +#[instrument(skip_all)] +fn should_appear_in_profile(kitty: Cat) { + sleep(QUITE_LONG) +} +``` + +Then either compile Zed with `ZTRACING=1 cargo r --release`. The release build is optional but highly recommended as like every program Zeds performance characteristics change dramatically with optimizations. You do not want to chase slowdowns that do not exist in release. + +## One time Setup/Building the profiler: + +Download the profiler: +[linux x86_64](https://zed-tracy-import-miniprofiler.nyc3.digitaloceanspaces.com/tracy-profiler-linux-x86_64) +[macos aarch64](https://zed-tracy-import-miniprofiler.nyc3.digitaloceanspaces.com/tracy-profiler-0.13.0-macos-aarch64) + +### Alternative: Building it yourself + +- Clone the repo at git@github.com:wolfpld/tracy.git +- `cd profiler && mkdir build && cd build` +- Run cmake to generate build files: `cmake -G Ninja -DCMAKE_BUILD_TYPE=Release ..` +- Build the profiler: `ninja` +- [Optional] move the profiler somewhere nice like ~/.local/bin on linux + +## Usage + +Open the profiler (tracy-profiler), you should see zed in the list of `Discovered clients` click it. +image + +To find functions that take a long time follow this image: +image + # Task/Async profiling Get a profile of the zed foreground executor and background executors. Check if @@ -23,11 +63,17 @@ look at the results live. ## Setup/Building the importer: +Download the importer +[linux x86_64](https://zed-tracy-import-miniprofiler.nyc3.digitaloceanspaces.com/tracy-import-miniprofiler-linux-x86_64) +[mac aarch64](https://zed-tracy-import-miniprofiler.nyc3.digitaloceanspaces.com/tracy-import-miniprofiler-macos-aarch64) + +### Alternative: Building it yourself + - Clone the repo at git@github.com:zed-industries/tracy.git on v0.12.2 branch -- `cd profiler && mkdir build && cd build` +- `cd import && mkdir build && cd build` - Run cmake to generate build files: `cmake -G Ninja -DCMAKE_BUILD_TYPE=Release ..` - Build the importer: `ninja` -- Run the impoter on the trace file: `./tracy-import-miniprofiler /path/to/trace.miniprof /path/to/output.tracy` +- Run the importer on the trace file: `./tracy-import-miniprofiler /path/to/trace.miniprof /path/to/output.tracy` - Open the trace in tracy: - If you're on windows download the v0.12.2 version from the releases on the upstream repo - If you're on other platforms open it on the website: https://tracy.nereid.pl/ (the version might mismatch so your luck might vary, we need to host our own ideally..)