Poor performances when typing in rectangle selection #58

Open
opened 2015-06-06 07:48:35 -05:00 by nippur72 · 9 comments
nippur72 commented 2015-06-06 07:48:35 -05:00 (Migrated from github.com)

On a file with about 1000 lines of text and syntax highlighting turned on, making a rectangle selection with more ~15 lines makes editing inside the selection very slow, dropping to something like 1 character per second.

On a file with about 1000 lines of text and syntax highlighting turned on, making a rectangle selection with more ~15 lines makes editing inside the selection very slow, dropping to something like 1 character per second.
zaksmolen commented 2018-01-10 13:39:04 -06:00 (Migrated from github.com)

I am still noticing this with current versions of AvalonEdit. I even turned off syntax highlighting and collapsing and even so, when I have a decent size block selection and try to type sometimes it takes a second per character.

Anyone have any ideas about fixes or optimizations? We unfortunately have a lot of people doing block selecting in our application...

I am still noticing this with current versions of AvalonEdit. I even turned off syntax highlighting and collapsing and even so, when I have a decent size block selection and try to type sometimes it takes a second per character. Anyone have any ideas about fixes or optimizations? We unfortunately have a lot of people doing block selecting in our application...
zaksmolen commented 2018-01-10 14:01:12 -06:00 (Migrated from github.com)

I have noticed that some of the things mentioned in #9 do help. Turning off space showing does make it a little faster, but we need spaces shown, and also it really seems to happen more with block select.

I have noticed that some of the things mentioned in #9 do help. Turning off space showing does make it a little faster, but we need spaces shown, and also it really seems to happen more with block select.
goswinr commented 2020-07-22 05:11:01 -05:00 (Migrated from github.com)

@siegfriedpammer could this be fixed by using Document.BeginUpdate() and Document.EndUpdate()
Or are you doing this already?
Could you point me at the relevant code, so that I can maybe try a PR ...

@siegfriedpammer could this be fixed by using [`Document.BeginUpdate() `](http://avalonedit.net/documentation/html/d2f40c5c-7f5f-8a07-208e-702288f4e19f.htm) and `Document.EndUpdate()` Or are you doing this already? Could you point me at the relevant code, so that I can maybe try a PR ...
zaksmolen commented 2020-09-01 12:45:29 -05:00 (Migrated from github.com)

I would be happy to take a look at this as well if someone could point me to the relevant area in the code. We finally were able to update our VS version so I can actually give fixing this a try!
Our users are literally copy/pasting in/out of WordPad or NP++ in order to do block selection and typing because that's faster than trying to do it in the editor.

I would be happy to take a look at this as well if someone could point me to the relevant area in the code. We finally were able to update our VS version so I can actually give fixing this a try! Our users are literally copy/pasting in/out of WordPad or NP++ in order to do block selection and typing because that's faster than trying to do it in the editor.
zaksmolen commented 2020-09-16 08:51:54 -05:00 (Migrated from github.com)

@goswinr I'm looking at the code and they do seem to have that area of code wrapped with using (textArea.Document.RunUpdate()) (so it does begin/end update), so that's not going to change anything.

I did some benchmark testing on my brand new and decently high-spec computer, timing this section of the code:

foreach (SelectionSegment lineSegment in this.Segments.Reverse()) {
	ReplaceSingleLineText(textArea, lineSegment, newText, out insertionLength);
	totalInsertionLength += insertionLength;
	firstInsertionLength = insertionLength;
}

~100 lines took consistently 1.5-4 seconds
~500 lines took consistently almost a full minute

Looking a little deeper, the slowest part of ReplaceSingleLineText() seems to be the Document.Insert() and Document.Replace() calls. To similar examples as before:
~180 lines too about 22ms per call
~540 lines took about 125ms per call

So first off, even without too many lines, that's quite slow for an action that's done for each line. 22ms * 180 lines is about 4 seconds just for the Insert() calls. That means 4+ seconds per character press if you're trying to type in just 180 lines. With 540 lines it took over a full minute, again meaning that if you're trying to type in a block selection, you have to wait over a minute per key press.

I'm curious why the time in that function jumps so high. A 3x increase in lines consistently increased the call time by 5x, and that's nowhere near the max amount of lines our users would want to be able to select.

@goswinr I'm looking at the code and they do seem to have that area of code wrapped with `using (textArea.Document.RunUpdate())` (so it does begin/end update), so that's not going to change anything. I did some benchmark testing on my brand new and decently high-spec computer, timing this section of the code: ``` foreach (SelectionSegment lineSegment in this.Segments.Reverse()) { ReplaceSingleLineText(textArea, lineSegment, newText, out insertionLength); totalInsertionLength += insertionLength; firstInsertionLength = insertionLength; } ``` ~100 lines took consistently 1.5-4 seconds ~500 lines took consistently almost a full minute Looking a little deeper, the slowest part of `ReplaceSingleLineText()` seems to be the `Document.Insert()` and `Document.Replace()` calls. To similar examples as before: ~180 lines too about 22ms per call ~540 lines took about 125ms per call So first off, even without too many lines, that's quite slow for an action that's done for each line. 22ms * 180 lines is about 4 seconds just for the `Insert()` calls. That means 4+ seconds per character press if you're trying to type in just 180 lines. With 540 lines it took over a full minute, again meaning that if you're trying to type in a block selection, you have to wait over a minute per key press. I'm curious why the time in that function jumps so high. A 3x increase in lines consistently increased the call time by 5x, and that's nowhere near the max amount of lines our users would want to be able to select.
zaksmolen commented 2020-09-16 11:22:22 -05:00 (Migrated from github.com)

Just to add more as I debug, 90+% of the time is in TextArea.OnDocumentChanged() and almost all of that is the selection.UpdateOnDocumentChange(e) line. So it's the UpdateOnDocumentChange() method of RectangularSelection.

I'm not sure why the selection needs to be updated after each line of a change, and not just at the end. I.e. it seems like this update should be deferred by some mechanism if the change is triggered by a rectangular selection action.

Just for testing I commented out the changed event call (TextDocument.cs around line 877), it didn't seem to have any changes to behavior (visually things still seem to update) but the 500 line change takes 1-1.5 seconds per character, an order of magnitude difference. 100 lines was still the slightest bit jumpy, but markedly better at around 0.2-0.25 seconds for per character.

Also, just a note, the debugging output to time things that I have been putting in for testing is actually slowing stuff down. With no debugging output, and only timing the whole change, it takes on average about 0.1 seconds per character press for 500 lines. But for the purpose of debugging, the overhead added should be relatively constant (make 2 DateTimes, subtract them, and log it to the console).

Just to add more as I debug, 90+% of the time is in `TextArea.OnDocumentChanged()` and almost all of that is the `selection.UpdateOnDocumentChange(e)` line. So it's the `UpdateOnDocumentChange()` method of `RectangularSelection`. I'm not sure why the selection needs to be updated after each line of a change, and not just at the end. I.e. it seems like this update should be deferred by some mechanism if the change is triggered by a rectangular selection action. Just for testing I commented out the changed event call (TextDocument.cs around line 877), it didn't seem to have any changes to behavior (visually things still seem to update) but the 500 line change takes 1-1.5 seconds per character, an order of magnitude difference. 100 lines was still the slightest bit jumpy, but markedly better at around 0.2-0.25 seconds for per character. Also, just a note, the debugging output to time things that I have been putting in for testing is actually slowing stuff down. With no debugging output, and only timing the whole change, it takes on average about 0.1 seconds per character press for 500 lines. But for the purpose of debugging, the overhead added should be relatively constant (make 2 DateTimes, subtract them, and log it to the console).
zaksmolen commented 2020-09-16 14:23:24 -05:00 (Migrated from github.com)

Ugh, well the side effect of not calling Changed() around line 877 is that it doesn't update the caret for normal typing.

Ugh, well the side effect of not calling `Changed()` around line 877 is that it doesn't update the caret for normal typing.
goswinr commented 2021-01-04 16:46:04 -06:00 (Migrated from github.com)

@zaksmolen I could significantly improve the performance of typing in a rectangle selection by using TextArea.PreviewTextInput event , then doing the block edit myself via a Stringbuilder and then call doc.Replace only once. maybe something similar might help you. Changing the font or reducing the syntax highlighting might help too see https://github.com/icsharpcode/AvalonEdit/issues/252

@zaksmolen I could significantly improve the performance of typing in a rectangle selection by using TextArea.PreviewTextInput event , then doing the block edit myself via a Stringbuilder and then call doc.Replace only once. maybe something similar might help you. Changing the font or reducing the syntax highlighting might help too see https://github.com/icsharpcode/AvalonEdit/issues/252
zaksmolen commented 2021-03-08 12:09:49 -06:00 (Migrated from github.com)

I believe I have finally resolved this in pull request 269.

I believe I have finally resolved this in pull request 269.
Sign in to join this conversation.
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-icsharpcode/AvalonEdit#58
No description provided.