-
Notifications
You must be signed in to change notification settings - Fork 196
improve replace performance take 2 (this time I have confirmed substantial improvements in the profiler) #1051
base: master
Are you sure you want to change the base?
Conversation
There was one test failure I haven't figured out. I do believe that the profiling results still give an accurate impression of what the speedup would be, though obviously I would need to fix the test failure if it's decided to approve this new approach. |
Is there some kind of bug with the V8 profiler Atom is using? I don't understand why it's splitting up the one call to |
Hey, nice job on this investigation @jedwards1211! This is a useful starting point.
I think it's important that we use individual
The problem is that the
☝️ All of this only applies to when replacing all markers though. When replacing just a single marker, we probably want to keep things as they are. Maybe we need to separate those two code paths instead of having them call a common method. |
Yeah I figured there are good reasons we wouldn't want to operate on the whole buffer as plain strings. And any idea why Also
That's good...for such a file though, assuming Atom is also capable of handling too many markers to fit in memory, do you think it would make more sense to do the replacements first and rebuild the markers later? |
@maxbrunsfeld sorry to bother again but do you have any idea why |
@jedwards1211 |
Oh I see. What about other kinds of markers though -- I'm guessing error underlines are another marker layer that would slow down calls to |
For this reason I'm wondering if we can get even better performance by devising a way to pass multiple changes to the text buffer at once, so that we only have to recompute the markers for each chunk of text once, rather than once for each marker being replaced within that chunk. |
Yes those features all use markers as well. It should be fine though; updating markers is already really efficient; in this case there’s just a huge amount of markers that don’t need to be updated. |
Well it's a bit absurd to imagine, but if for whatever reason there were 60000 diff markers, it would cause the same performance issue as 60000 search result markers, right? |
@maxbrunsfeld I did some more digging on this. The way changes are communicated to the marker layer doesn't seem to be the main culprit in my profiling results; instead I'm seeing
splice
calls from withinsetTextInBufferRange
taking the most time:I haven't figured out why each
splice
operation is taking from 0.5 - 1 millsecond, but it means that if 60000 markers get replaced, thesplice
s consume a combined total of around 45 seconds, which is indeed at least how long it took for the editor to respond (I stopped the profiler after about 40 seconds).When I changed
replace
to use plain JS string operations and then calledsetTextInBufferRange
once to replace the entire buffer text at the end, the same 60000 replacements took about 5.5 seconds, of which at least 4 seconds are probably mostly due to the destroy marker notifications.Description of the Change
Instead of calling
getTextInBufferRange
andsetTextInBufferRange
for each individual replacement, I get the entire text of the buffer, build up the replacement buffer text with native JS string operations, and replace the entire buffer text with a single call tosetTextInBufferRange
at the end.Alternate Designs
This is really just an experiment right now to contribute to the discussion of
text-buffer
performanceBenefits
In my profiling test case (replacing "foo" with "hello" in a buffer with 60000 lines of "foo bar baz qux")
The time to replace is reduced from over 45 seconds to 5.5 seconds.
Possible Drawbacks
Unfortunately, replacing the entire buffer text clears the selection, so I doubt you will want to merge this PR as-is.
Applicable Issues
#653