editor: More perf work (#49465)
Seems that `SmallVec::clone` is pretty expensive in a generic case, and specialising it improves the performance quite a bit! Release Notes: - Improved performance of different building blocks within the MultiBuffer. --------- Co-authored-by: Lukas Wirth <lukas@zed.dev>
This commit is contained in:
1 parent
dc41f71f57
commit
1957a43ef1
5 files changed
+60
-49
No files matched your search
@@ -914,28 +914,25 @@ impl BufferDiffInner<language::BufferSnapshot> {
|
||||
buffer: &'a text::BufferSnapshot,
|
||||
secondary: Option<&'a Self>,
|
||||
) -> impl 'a + Iterator<Item = DiffHunk> {
|
||||
let mut cursor = self.hunks.filter::<_, DiffHunkSummary>(buffer, filter);
|
||||
|
||||
let anchor_iter = iter::from_fn(move || {
|
||||
cursor.next();
|
||||
cursor.item()
|
||||
})
|
||||
.flat_map(move |hunk| {
|
||||
[
|
||||
(
|
||||
&hunk.buffer_range.start,
|
||||
let anchor_iter = self
|
||||
.hunks
|
||||
.filter::<_, DiffHunkSummary>(buffer, filter)
|
||||
.flat_map(move |hunk| {
|
||||
[
|
||||
(
|
||||
hunk.buffer_range.start,
|
||||
hunk.diff_base_byte_range.start,
|
||||
hunk,
|
||||
&hunk.buffer_range.start,
|
||||
(
|
||||
hunk.buffer_range.start,
|
||||
hunk.diff_base_byte_range.start,
|
||||
hunk,
|
||||
),
|
||||
),
|
||||
),
|
||||
(
|
||||
&hunk.buffer_range.end,
|
||||
(hunk.buffer_range.end, hunk.diff_base_byte_range.end, hunk),
|
||||
),
|
||||
]
|
||||
});
|
||||
(
|
||||
&hunk.buffer_range.end,
|
||||
(hunk.buffer_range.end, hunk.diff_base_byte_range.end, hunk),
|
||||
),
|
||||
]
|
||||
});
|
||||
|
||||
let mut pending_hunks_cursor = self.pending_hunks.cursor::<DiffHunkSummary>(buffer);
|
||||
pending_hunks_cursor.next();
|
||||
|
||||
@@ -66,13 +66,27 @@ pub struct Lamport {
|
||||
}
|
||||
|
||||
/// A [version vector](https://en.wikipedia.org/wiki/Version_vector).
|
||||
#[derive(Clone, Default, Hash, Eq, PartialEq)]
|
||||
#[derive(Default, Hash, Eq, PartialEq)]
|
||||
pub struct Global {
|
||||
// 4 is chosen as it is the biggest count that does not increase the size of the field itself.
|
||||
// Coincidentally, it also covers all the important non-collab replica ids.
|
||||
values: SmallVec<[u32; 4]>,
|
||||
}
|
||||
|
||||
impl Clone for Global {
|
||||
fn clone(&self) -> Self {
|
||||
// We manually implement clone to avoid the overhead of SmallVec's clone implementation.
|
||||
// Using `from_slice` is faster than `clone` for SmallVec as we can use our `Copy` implementation of u32.
|
||||
Self {
|
||||
values: SmallVec::from_slice(&self.values),
|
||||
}
|
||||
}
|
||||
|
||||
fn clone_from(&mut self, source: &Self) {
|
||||
self.values.clone_from(&source.values);
|
||||
}
|
||||
}
|
||||
|
||||
impl Global {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
|
||||
@@ -2013,14 +2013,14 @@ impl LhsEditor {
|
||||
diff: Entity<BufferDiff>,
|
||||
lhs_cx: &mut Context<MultiBuffer>,
|
||||
) -> Option<(Vec<ExcerptId>, Vec<Vec<ExcerptId>>)> {
|
||||
let rhs_excerpt_ids: Vec<ExcerptId> =
|
||||
rhs_multibuffer.excerpts_for_path(&path_key).collect();
|
||||
|
||||
let Some(excerpt_id) = rhs_multibuffer.excerpts_for_path(&path_key).next() else {
|
||||
lhs_multibuffer.remove_excerpts_for_path(path_key, lhs_cx);
|
||||
return None;
|
||||
};
|
||||
|
||||
let rhs_excerpt_ids: Vec<ExcerptId> =
|
||||
rhs_multibuffer.excerpts_for_path(&path_key).collect();
|
||||
|
||||
let rhs_multibuffer_snapshot = rhs_multibuffer.snapshot(lhs_cx);
|
||||
let main_buffer = rhs_multibuffer_snapshot
|
||||
.buffer_for_excerpt(excerpt_id)
|
||||
|
||||
@@ -10,8 +10,8 @@ pub use anchor::{Anchor, AnchorRangeExt};
|
||||
|
||||
use anyhow::{Result, anyhow};
|
||||
use buffer_diff::{
|
||||
BufferDiff, BufferDiffEvent, BufferDiffSnapshot, DiffChanged, DiffHunk,
|
||||
DiffHunkSecondaryStatus, DiffHunkStatus, DiffHunkStatusKind,
|
||||
BufferDiff, BufferDiffEvent, BufferDiffSnapshot, DiffChanged, DiffHunkSecondaryStatus,
|
||||
DiffHunkStatus, DiffHunkStatusKind,
|
||||
};
|
||||
use clock::ReplicaId;
|
||||
use collections::{BTreeMap, Bound, HashMap, HashSet};
|
||||
@@ -2409,7 +2409,7 @@ impl MultiBuffer {
|
||||
diff: Entity<BufferDiff>,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let base_text_buffer_id = diff.read(cx).base_text(cx).remote_id();
|
||||
let base_text_buffer_id = diff.read(cx).base_text_buffer().read(cx).remote_id();
|
||||
let diff = diff.read(cx);
|
||||
let diff = DiffStateSnapshot {
|
||||
diff: diff.snapshot(cx),
|
||||
@@ -2474,7 +2474,7 @@ impl MultiBuffer {
|
||||
self.sync_mut(cx);
|
||||
|
||||
let diff = diff.read(cx);
|
||||
let base_text_buffer_id = diff.base_text(cx).remote_id();
|
||||
let base_text_buffer_id = diff.base_text_buffer().read(cx).remote_id();
|
||||
let Some(buffer_state) = self.buffers.get(&base_text_buffer_id) else {
|
||||
return;
|
||||
};
|
||||
@@ -2674,8 +2674,9 @@ impl MultiBuffer {
|
||||
}
|
||||
|
||||
pub fn add_inverted_diff(&mut self, diff: Entity<BufferDiff>, cx: &mut Context<Self>) {
|
||||
let base_text_buffer_id = diff.read(cx).base_text(cx).remote_id();
|
||||
let diff_change_range = 0..diff.read(cx).base_text(cx).len();
|
||||
let snapshot = diff.read(cx).base_text(cx);
|
||||
let base_text_buffer_id = snapshot.remote_id();
|
||||
let diff_change_range = 0..snapshot.len();
|
||||
self.snapshot.get_mut().has_inverted_diff = true;
|
||||
self.inverted_buffer_diff_changed(diff.clone(), diff_change_range, cx);
|
||||
self.diffs
|
||||
@@ -3965,25 +3966,24 @@ impl MultiBufferSnapshot {
|
||||
let query_range = range.start.to_point(self)..range.end.to_point(self);
|
||||
self.lift_buffer_metadata(query_range.clone(), move |buffer, buffer_range| {
|
||||
let diff = self.diffs.get(&buffer.remote_id())?;
|
||||
let iter: Box<dyn Iterator<Item = (DiffHunk, &BufferSnapshot, bool)>> =
|
||||
if diff.is_inverted {
|
||||
let buffer_start = buffer.point_to_offset(buffer_range.start);
|
||||
let buffer_end = buffer.point_to_offset(buffer_range.end);
|
||||
Box::new(
|
||||
diff.hunks_intersecting_base_text_range(
|
||||
buffer_start..buffer_end,
|
||||
diff.original_buffer_snapshot(),
|
||||
)
|
||||
.map(move |hunk| (hunk, buffer, true)),
|
||||
let iter = if diff.is_inverted {
|
||||
let buffer_start = buffer.point_to_offset(buffer_range.start);
|
||||
let buffer_end = buffer.point_to_offset(buffer_range.end);
|
||||
itertools::Either::Left(
|
||||
diff.hunks_intersecting_base_text_range(
|
||||
buffer_start..buffer_end,
|
||||
diff.original_buffer_snapshot(),
|
||||
)
|
||||
} else {
|
||||
let buffer_start = buffer.anchor_before(buffer_range.start);
|
||||
let buffer_end = buffer.anchor_after(buffer_range.end);
|
||||
Box::new(
|
||||
diff.hunks_intersecting_range(buffer_start..buffer_end, buffer)
|
||||
.map(move |hunk| (hunk, buffer, false)),
|
||||
)
|
||||
};
|
||||
.map(move |hunk| (hunk, buffer, true)),
|
||||
)
|
||||
} else {
|
||||
let buffer_start = buffer.anchor_before(buffer_range.start);
|
||||
let buffer_end = buffer.anchor_after(buffer_range.end);
|
||||
itertools::Either::Right(
|
||||
diff.hunks_intersecting_range(buffer_start..buffer_end, buffer)
|
||||
.map(move |hunk| (hunk, buffer, false)),
|
||||
)
|
||||
};
|
||||
Some(iter.filter_map(|(hunk, buffer, is_inverted)| {
|
||||
if hunk.is_created_file() && !self.all_diff_hunks_expanded {
|
||||
return None;
|
||||
|
||||
@@ -57,7 +57,7 @@ impl MultiBuffer {
|
||||
self.excerpts_by_path
|
||||
.get(path)
|
||||
.map(|excerpts| excerpts.as_slice())
|
||||
.unwrap_or(&[])
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.copied()
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user