Closed
Bug 1482798
Opened 7 years ago
Closed 6 years ago
Moving cursor in CodeMirror JsTerm when output is tall causes slow Reflow
Categories
(DevTools :: Console, defect, P1)
DevTools
Console
Tracking
(firefox63 fixed)
RESOLVED
FIXED
Firefox 63
Tracking | Status | |
---|---|---|
firefox63 | --- | fixed |
People
(Reporter: nchevobbe, Assigned: nchevobbe)
References
Details
(Keywords: perf)
Attachments
(2 files)
**Steps to reproduce**
1. Open the console
2. Evaluate "\n".repeat(9000) 3 times
3. In the input, Hit Shift + Enter to enter new lines
4. Hit Arrow up to move the cursor one line up
**Expected results**
Everything is smooth as it can be
**Actual results**
Moving the cursor looks quite slow
---
Here's a profile I recorded with the STR: https://perfht.ml/2B625WY
The culprit is this code in codeMirror:
```js
function kn(e){return e.lineSpace.offsetTop}
```
In the profile, we can see a 178ms reflow caused by offsetTop.
Here's another profile when the output contains only 3 one-line logs: https://perfht.ml/2B6cPEN . We can see that there's nothing too costly happening.
Also, if you :
- clear the console
- evaluate `"\n".repeat(10000)` (this will create a longString)
- go to the top
- click on the arrow before the string
- scroll to the very bottom
- in the input, hit Shift + Enter to have multiple lines
- and hit ArrowUp to navigate the cursor one line up
you'll be able to see that this is not as costly as with the 9000 lines tall evaluation (https://perfht.ml/2B63Fbl).
Comment 1•7 years ago
|
||
Looks like it corresponds to this line in the CM source: https://github.com/codemirror/CodeMirror/blob/3eaa89bfdb980a22e903b0a697cbe41bf8bd446a/src/measurement/position_measurement.js#L17
Assignee | ||
Comment 2•7 years ago
|
||
Brad, could you have a look at this profile: https://perfht.ml/2B625WY and see why the reflow takes so long ?
I tried to make sense of it but oculdn't really tell what's happening on platform side.
Flags: needinfo?(bwerth)
Comment 3•7 years ago
|
||
Presuming that the reflow is unavoidable, the costly work is in two calls to nsHTMLScrollFrame::ReflowScrolledFrame which appear to be the same element, reflowed twice. I'll see if I can find a way to reduce this to one reflow, which will cut the reflow time in half.
Assignee: nobody → bwerth
Flags: needinfo?(bwerth)
Comment 4•7 years ago
|
||
Of course, since the profile data is just a sample, it could just be that many similar elements are being reflowed and that makes it look like two large reflows of the same element. I'll learn what I can.
Comment 5•7 years ago
|
||
In comment 3, I proposed that there was a nsScrolledFrame that is being reflowed twice and I've confirmed that is the case. I haven't yet figured out why it's getting reflowed the second time (other than that a parent is getting reflowed). Anyway, there's still some chance we can find a way to cut this time in half.
But why is it slow in the first place when the very similar longString case from commment 0 is not slow? New theory: the code that calls offsetTop also changes style on some element, and makes some change to a pseudoelement that adds a div into the DOM. That added div causes an expensive reflow. I can't make sense of the JS stack to figure out what restyle is being done.
Comment 6•7 years ago
|
||
To be clear, the new theory in comment 5 is indicated by the call stacks where reflow is requested. The reflow comes from the addition of a div into the DOM, after some style changes are being processed.
Assignee | ||
Comment 7•7 years ago
|
||
It looks like we don't really need a grid layout anymore
for the message body AND it significantly reduces the time
spent on reflow.
Assignee | ||
Comment 8•7 years ago
|
||
(In reply to Nicolas Chevobbe [:nchevobbe] from comment #7)
> Created attachment 9002663 [details]
> Bug 1482798 - Use a flex layout for message body; r=bgrins.
>
> It looks like we don't really need a grid layout anymore
> for the message body AND it significantly reduces the time
> spent on reflow.
This patch seems to improve reflow:
Without patch: https://perfht.ml/2N56U4l (~150ms)
With patch: https://perfht.ml/2N76paa (~80ms)
Assignee | ||
Comment 9•7 years ago
|
||
The "Why codeMirror is calling offsetTop (but also scrollTop, getBoundingClientRect, …) causing this reflow" is because it checks if the editor should be scrolled in response to a key stroke.
This may be something we try to fix in the codeMirror repo at some point.
Comment 10•7 years ago
|
||
I'm still curious if there is any JS that is setting a style with with a ::before or ::after pseudoelement with content styling. That's one explanation that would explain why the styling is triggering a reflow as evidenced by the call stack. In the meanwhile, switching from grid to flex looks like it avoids the double reflow, which is great. I'll see if I can learn more from the JS stack and find the styling change.
Comment 11•7 years ago
|
||
Comment on attachment 9002663 [details]
Bug 1482798 - Use a flex layout for message body; r=bgrins.
Brian Grinstead [:bgrins] has approved the revision.
Attachment #9002663 -
Flags: review+
Comment 12•7 years ago
|
||
(In reply to Brad Werth [:bradwerth] from comment #10)
> I'm still curious if there is any JS that is setting a style with with a
> ::before or ::after pseudoelement with content styling. That's one
> explanation that would explain why the styling is triggering a reflow as
> evidenced by the call stack. In the meanwhile, switching from grid to flex
> looks like it avoids the double reflow, which is great. I'll see if I can
> learn more from the JS stack and find the styling change.
Thanks for looking into this! I'm also curious if there's any particular flexbox perf improvements to be had after this patch lands (it still seems like we should be able to be faster than 80ms for this layout). We've already filed a couple of bugs against the flexbox perf metabug related to the console (Bug 1408190 and Bug 1410464) - I'm assuming one of those will cover it, but we can file a new one if you think this is a distinct issue from than those.
Comment 13•7 years ago
|
||
Pushed by nchevobbe@mozilla.com:
https://hg.mozilla.org/integration/autoland/rev/038353b1a3c5
Use a flex layout for message body; r=bgrins.
Assignee | ||
Comment 14•7 years ago
|
||
Should we add the leave-open bug here so we can land more fixes (if we can) here ?
Comment 15•7 years ago
|
||
(In reply to Nicolas Chevobbe [:nchevobbe] from comment #14)
> Should we add the leave-open bug here so we can land more fixes (if we can)
> here ?
I'd say let's do any other fixes in separate bugs so it's easier to track across releases, talos results, etc.
Comment 16•7 years ago
|
||
Okay, I'll open a new bug. There's definitely more work to do since the key events shouldn't be causing reflow at all (and don't in the alternate longString case noted in comment 0).
Assignee | ||
Comment 17•7 years ago
|
||
So here's a profile with saner JS stacktrace in codeMirror (you can apply the patch to have the same thing). This is on top of the grid to flex patch: https://perfht.ml/2wkogTC
You can see the "scrollPosIntoView" function leading to the offsetTop access (and thus reflow).
But this is not the only place a reflow is triggered, If I return a fixed value in `paddingTop` instead of calling offsetTop, then you hit other access to reflow-needed property (scrollTop) or function (getBoundingClientRect).
Assignee | ||
Comment 18•7 years ago
|
||
(In reply to Brad Werth [:bradwerth] from comment #10)
> I'm still curious if there is any JS that is setting a style with with a
> ::before or ::after pseudoelement with content styling. That's one
> explanation that would explain why the styling is triggering a reflow as
> evidenced by the call stack. In the meanwhile, switching from grid to flex
> looks like it avoids the double reflow, which is great. I'll see if I can
> learn more from the JS stack and find the styling change.
Is this when only moving the cursor or when typing a letter ?
If it's when typing, it may be the "completionText" feature, where we use an ::after to display that.
The JS call is here https://searchfox.org/mozilla-central/rev/71ef4447db179639be9eff4471f32a95423962d7/devtools/client/sourceeditor/editor.js#1289-1303 and the CSS for it: https://searchfox.org/mozilla-central/rev/71ef4447db179639be9eff4471f32a95423962d7/devtools/client/themes/webconsole.css#351-354
Comment 19•7 years ago
|
||
(In reply to Nicolas Chevobbe [:nchevobbe] from comment #18)
> (In reply to Brad Werth [:bradwerth] from comment #10)
> > I'm still curious if there is any JS that is setting a style with with a
> > ::before or ::after pseudoelement with content styling. That's one
> > explanation that would explain why the styling is triggering a reflow as
> > evidenced by the call stack. In the meanwhile, switching from grid to flex
> > looks like it avoids the double reflow, which is great. I'll see if I can
> > learn more from the JS stack and find the styling change.
>
> Is this when only moving the cursor or when typing a letter ?
For me, it's occurring from cursor movement AND typing of letters. With your de-uglified codemirror JS, I should be able to learn more.
Assignee | ||
Comment 20•7 years ago
|
||
So, I was looking at the differences between the longString example and the regular one.
The longString is contained in an object-inspector node, which display is inline-block.
So I added a display:inline-block to the .objectBox.objectBox-string element like below:
> <div class="cm-s-mozilla message javascript result log" aria-live="polite">
> <span data-indent="0" class="indent" style="width: 0px;"></span>
> <span class="icon" title="Log" aria-live="off"></span>
> <span class="message-body-wrapper">
> <span class="message-flex-body">
> <span class="message-body devtools-monospace">
> <span class="objectBox objectBox-string" style="display: inline-block;">""</span>
> </span>
> <span class="message-location devtools-monospace"></span>
> </span>
> </span>
> </div>
And then, voila, no more costly reflows on keyboard move !
So, I'm not sure this is the thing to do right now (not sure what the impact on the UI is), but I hope this will help you Brad.
Comment 21•7 years ago
|
||
Well done! That's a surprising result. I propose you add this fix to the other, and land this bug. I will open a new issue to investigate why the reflow is happening at all, and assign myself to that bug. Since I'm not contributing any patches to this bug, I'm taking myself off it.
Assignee: bwerth → nobody
Updated•7 years ago
|
Assignee: nobody → nchevobbe
Status: NEW → ASSIGNED
Comment 22•7 years ago
|
||
bugherder |
Status: ASSIGNED → RESOLVED
Closed: 7 years ago
status-firefox63:
--- → fixed
Resolution: --- → FIXED
Target Milestone: --- → Firefox 63
Assignee | ||
Comment 23•7 years ago
|
||
So, the display: inline-block things only works for the case described in Comment 0 (i.e. 1 tall message).
Evaluating
```js
for (i = 0; i < 200; i++) {
console.log(i)
}
```
And then moving the cursor will still be slow.
Assignee | ||
Comment 24•7 years ago
|
||
I tried to use `inputStyle: "contenteditable"` on the editor config, which make it use a contenteditable div. The idea was that since it's native, it doesn't need custom code to check if the ceontainer should be scrolled when moving the cursor.
And it works, no more reflow in the case of this specific bug (i.e. moving cursor).
_But_, they're still there when typing, which is the primary interaction in the input, so I'm not sure it's worth investigating on that side (it may causes some small issue we need to take care of).
Comment 25•7 years ago
|
||
(In reply to Nicolas Chevobbe [:nchevobbe] from comment #24)
> I tried to use `inputStyle: "contenteditable"` on the editor config, which
> make it use a contenteditable div. The idea was that since it's native, it
> doesn't need custom code to check if the ceontainer should be scrolled when
> moving the cursor.
> And it works, no more reflow in the case of this specific bug (i.e. moving
> cursor).
> _But_, they're still there when typing, which is the primary interaction in
> the input, so I'm not sure it's worth investigating on that side (it may
> causes some small issue we need to take care of).
Yeah, sounds like it's not a fix for this particular issue. Although we have talked about switching to it for accessibility sake (at least for reading the contents of the input field). But I'd like to know if/how it relates to the in-development version of CM that is supposed to have better accessibility before we spend too much time testing it.
Comment 26•7 years ago
|
||
(In reply to Nicolas Chevobbe [:nchevobbe] from comment #24)
> I tried to use `inputStyle: "contenteditable"` on the editor config, which
> make it use a contenteditable div. The idea was that since it's native, it
> doesn't need custom code to check if the ceontainer should be scrolled when
> moving the cursor.
> And it works, no more reflow in the case of this specific bug (i.e. moving
> cursor).
> _But_, they're still there when typing, which is the primary interaction in
> the input, so I'm not sure it's worth investigating on that side (it may
> causes some small issue we need to take care of).
I think this bug should stay open until we have a general solution. Here are the sources of slowness:
1) Slowness in flex container unnecessary sibling reflows. Bug 1377253 is tracking this and I'm told we'll have a solution there soon. Alternatively, landing Bug 1150081 will provide a solution too.
2) If vertical scrollbars are shown when content overflows, it forces a second layout of this slow flex container (discussed in Bug 1486996). There's probably nothing we can do about that since the console output area should show a vertical scrollbar in this situation. I'll play around with the overflow property values and see if that can help.
Comment 27•7 years ago
|
||
(In reply to Brad Werth [:bradwerth] from comment #26)
> 2) If vertical scrollbars are shown when content overflows, it forces a
> second layout of this slow flex container (discussed in Bug 1486996).
> There's probably nothing we can do about that since the console output area
> should show a vertical scrollbar in this situation. I'll play around with
> the overflow property values and see if that can help.
As expected, adding .webconsole-output { overflow-y: scroll; } cuts the reflow time in half, at the expense of always showing the scrollbar.
Comment 28•7 years ago
|
||
(In reply to Brad Werth [:bradwerth] from comment #27)
> (In reply to Brad Werth [:bradwerth] from comment #26)
> > 2) If vertical scrollbars are shown when content overflows, it forces a
> > second layout of this slow flex container (discussed in Bug 1486996).
> > There's probably nothing we can do about that since the console output area
> > should show a vertical scrollbar in this situation. I'll play around with
> > the overflow property values and see if that can help.
>
> As expected, adding .webconsole-output { overflow-y: scroll; } cuts the
> reflow time in half, at the expense of always showing the scrollbar.
By the way, the patch in Bug 1487457 does some markup simplification and overflow changes to speed up reflow.
Depends on: 1487457
Assignee | ||
Updated•7 years ago
|
Priority: -- → P1
Assignee | ||
Comment 29•6 years ago
|
||
This is definitely fixed by Bug 1490890. We'll watch typing performance with a damp test in the future (See Bug 1487359).
Status: REOPENED → RESOLVED
Closed: 7 years ago → 6 years ago
Resolution: --- → FIXED
You need to log in
before you can comment on or make changes to this bug.
Description
•