WIP: Improve performance of Wrap Map (#16761)

We've ran into performance issues when reinserting new blocks into the
assistant panel; in profiles WrapMap showed up, as we try to query wrap
boundaries over and over, which is a hidden O(n^2) - for each block, we
may potentially look at all of the Wraps. This PR alleviates this issue
by storing away previously resolved wrap range; consecutive iterations
can often reuse it.
This should help with performance of Assistant Panel with long
conversations.

Release Notes:

- Improved performance of assistant panel with large # of text.
This commit is contained in:
Piotr Osiewicz 2024-08-23 18:59:30 +02:00 committed by GitHub
parent 30a677e257
commit 783cccf95d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -783,11 +783,13 @@ impl<'a> BlockMapWriter<'a> {
&mut self,
blocks: impl IntoIterator<Item = BlockProperties<Anchor>>,
) -> Vec<CustomBlockId> {
let mut ids = Vec::new();
let blocks = blocks.into_iter();
let mut ids = Vec::with_capacity(blocks.size_hint().1.unwrap_or(0));
let mut edits = Patch::default();
let wrap_snapshot = &*self.0.wrap_snapshot.borrow();
let buffer = wrap_snapshot.buffer_snapshot();
let mut previous_wrap_row_range: Option<Range<u32>> = None;
for block in blocks {
let id = CustomBlockId(self.0.next_block_id.fetch_add(1, SeqCst));
ids.push(id);
@ -797,11 +799,18 @@ impl<'a> BlockMapWriter<'a> {
let wrap_row = wrap_snapshot
.make_wrap_point(Point::new(point.row, 0), Bias::Left)
.row();
let start_row = wrap_snapshot.prev_row_boundary(WrapPoint::new(wrap_row, 0));
let end_row = wrap_snapshot
.next_row_boundary(WrapPoint::new(wrap_row, 0))
.unwrap_or(wrap_snapshot.max_point().row() + 1);
let (start_row, end_row) = {
previous_wrap_row_range.take_if(|range| !range.contains(&wrap_row));
let range = previous_wrap_row_range.get_or_insert_with(|| {
let start_row = wrap_snapshot.prev_row_boundary(WrapPoint::new(wrap_row, 0));
let end_row = wrap_snapshot
.next_row_boundary(WrapPoint::new(wrap_row, 0))
.unwrap_or(wrap_snapshot.max_point().row() + 1);
start_row..end_row
});
(range.start, range.end)
};
let block_ix = match self
.0
.custom_blocks
@ -881,6 +890,7 @@ impl<'a> BlockMapWriter<'a> {
let buffer = wrap_snapshot.buffer_snapshot();
let mut edits = Patch::default();
let mut last_block_buffer_row = None;
let mut previous_wrap_row_range: Option<Range<u32>> = None;
self.0.custom_blocks.retain(|block| {
if block_ids.contains(&block.id) {
let buffer_row = block.position.to_point(buffer).row;
@ -889,21 +899,32 @@ impl<'a> BlockMapWriter<'a> {
let wrap_row = wrap_snapshot
.make_wrap_point(Point::new(buffer_row, 0), Bias::Left)
.row();
let start_row = wrap_snapshot.prev_row_boundary(WrapPoint::new(wrap_row, 0));
let end_row = wrap_snapshot
.next_row_boundary(WrapPoint::new(wrap_row, 0))
.unwrap_or(wrap_snapshot.max_point().row() + 1);
let (start_row, end_row) = {
previous_wrap_row_range.take_if(|range| !range.contains(&wrap_row));
let range = previous_wrap_row_range.get_or_insert_with(|| {
let start_row =
wrap_snapshot.prev_row_boundary(WrapPoint::new(wrap_row, 0));
let end_row = wrap_snapshot
.next_row_boundary(WrapPoint::new(wrap_row, 0))
.unwrap_or(wrap_snapshot.max_point().row() + 1);
start_row..end_row
});
(range.start, range.end)
};
edits.push(Edit {
old: start_row..end_row,
new: start_row..end_row,
})
}
self.0.custom_blocks_by_id.remove(&block.id);
false
} else {
true
}
});
self.0
.custom_blocks_by_id
.retain(|id, _| !block_ids.contains(id));
self.0.sync(wrap_snapshot, edits);
}
}