Web console recreates React elements for all messages in each render
Categories
(DevTools :: Console, defect, P2)
Tracking
(Not tracked)
People
(Reporter: bradwerth, Unassigned)
References
Details
Attachments
(2 files, 7 obsolete files)
React rendering compares the elements (objects) submitted to it to determine if DOM changes are necessary. In order to minimize the work done by React, it is most efficient for an unchanged console message to be represented by the same object on subsequent renders. This cuts down on calls to React createElement
, which shows up in performance profiles as a significant factor when many messages are generated.
Reporter | ||
Comment 1•4 years ago
|
||
This patch trades memory for efficiency. This makes the ConsoleOutput store
the React elements it sent for rendering on the last render call. On the next
render call, it then re-sends any existing objects it is storing, creates the
new ones, and then deletes any forgotten objects.
Reporter | ||
Comment 2•4 years ago
|
||
I think this is showing improvement in most console tests. There is a regression in console.objectexpanded.close.DAMP
test, but the results are within the margin of error -- analysis marks this one as medium confidence. I'll seek review.
Comment 3•4 years ago
|
||
(In reply to Brad Werth [:bradwerth] from comment #2)
I think this is showing improvement in most console tests. There is a regression in
console.objectexpanded.close.DAMP
test, but the results are within the margin of error -- analysis marks this one as medium confidence. I'll seek review.
You should toggle "hide uncertain results", and then it only shows improvements.
But this is surprising that we don't see more wins on the console. It might be worth pushing your base revision to DAMP to get more confidences. When using "last x days of m-c" you get mixed results if anything regressed/improved in these last x days.
Reporter | ||
Comment 4•4 years ago
|
||
(In reply to Alexandre Poirot [:ochameau] from comment #3)
You should toggle "hide uncertain results", and then it only shows improvements.
Yes, I had seen that, but I didn't want to elide a possible regression. Another low-confidence result is the improvement to complicated.webconsole.reload.DAMP
. If reload avoids re-creating the ConsoleOutput
object (does it?) then I would expect this test to show the improvement that it apparently does.
Reporter | ||
Comment 5•4 years ago
|
||
Once created, these objects are not modified further. This ensures that React
can skip over some equality checks.
Updated•4 years ago
|
Reporter | ||
Comment 6•4 years ago
|
||
Depends on D87471
Reporter | ||
Comment 7•4 years ago
|
||
Depends on D90757
Updated•4 years ago
|
Reporter | ||
Comment 8•4 years ago
|
||
These patches don't yet work, but do represent the only promising approach I've found for reducing the number of calls to React.createElement.
Reporter | ||
Comment 9•4 years ago
|
||
The patches work as intended now. The speedup is more modest than I anticipated. Here's some times from different browser builds (reload with the console visible) to compare on this test file:
Chrome: 0.1s
Firefox Release (unpatched): 0.5s
Firefox Debug (unpatched): 80s - 100s
Firefox Debug (patched): 65s - 75s
So perhaps this is giving us a 25% reduction in runtime. I would project this would reduce the Release time to 0.4s. I'll run a new profile and see what the new opportunities are for improvement. If they are sufficiently related to this work, I'll keep adding to the patches in this bug. If not, I'll file a new bug.
Reporter | ||
Comment 10•4 years ago
•
|
||
The new profile https://share.firefox.dev/362rRZW confirms that the patch is working as intended. ConsoleOutput.render
is now 2.2% of the runtime section of interest. There aren't other obvious large blocks to pursue. Here's some relevant items:
Frame.render: 6.4%
Message.render: 7.1%
MessageContainer.render: 7.8%
ConsoleOutput.render: 2.2%
The rendering methods combined are now about 23% of the runtime -- comparable to the gains already achieved by the reduction to time spent in ConsoleOutput.render
. Even if we could somehow reduce render to 0s, we'd only shorten runtime by that much. There aren't obvious bad call patterns here.
MessageContainer.shouldComponentUpdate: 4.1%
There might be gains to be made here. The shouldComponentUpdate
method should always be fast in order to be useful. Otherwise, just always update!
Document.createElementNS: 2.4%
This is cost of modifying the DOM.
PresShell::FlushPendingNotifications: 5.5%
This is our layout cost. Seems reasonable, though we might be able to reduce it by calculating the height of each console item (after initial layout). This is evidence that virtualized scrolling is not relevant to this slow case.
ActivityStreamProvider.getTopFrecentSites: 2.8%
I have no idea what this is doing here. Even if it's just a coincidence that this scheduled operation overlapped with my profile, it's still true that this operation is much slower than it should be.
messages reducer: 4.7%
This is split between time in addMessages
and cloneState
. There may be opportunities here.
Okay, that's not everything, but it's all the notable chunks that we might be able to affect. I'll see if I can add something in this patch stack to reduce time in MessageContainer.shouldComponentUpdate
and in the messages reducer. I don't know what to do about ActivityStreamProvider.getTopFrecentSites
.
Reporter | ||
Comment 11•4 years ago
|
||
The call to MessageContainer.shouldComponentUpdate function is expensive due
to comparison of native properties. Since MessageContainers are only ever
regenerated when they change, they never need to update and the
shouldComponentUpdate function is totally unnecessary. In React, that is
handled by defining MessageContainer as a PureComponent, which has a fast
default shouldComponentUpdate call.
Depends on D90758
Reporter | ||
Comment 12•4 years ago
|
||
That's as far as I can get, performance-wise. I'm going to add another part to address test failures, then seek review.
Updated•4 years ago
|
Updated•4 years ago
|
Updated•4 years ago
|
Updated•4 years ago
|
Reporter | ||
Comment 13•4 years ago
|
||
This is starting to look good. New try run: https://treeherder.mozilla.org/#/jobs?repo=try&revision=f2b8f1a6396474da34076c2ca470f0a609bd33fc
Updated•4 years ago
|
Reporter | ||
Comment 14•4 years ago
|
||
Some tests fail intermittently due to messages being sent after the transport
has been closed. Those messages are safely ignorable.
Depends on D91230
Reporter | ||
Comment 15•4 years ago
|
||
Finally ready: https://treeherder.mozilla.org/#/jobs?repo=try&revision=5a4a5d78cb2e9300719b2e4e67347ef30420d900. Seeking review.
Reporter | ||
Comment 16•4 years ago
|
||
Reporter | ||
Comment 17•4 years ago
|
||
Depends on D91976
Updated•4 years ago
|
Reporter | ||
Comment 18•4 years ago
|
||
I'm going to add a blocker bug to this bug that adds a console logging DAMP test, so we have comparable performance before we try to land this.
Reporter | ||
Comment 19•4 years ago
|
||
(In reply to Brad Werth [:bradwerth] from comment #18)
I'm going to add a blocker bug to this bug that adds a console logging DAMP test, so we have comparable performance before we try to land this.
It looks like Bug 1593728 will serve as that blocker.
Reporter | ||
Comment 20•4 years ago
|
||
New try run that hopefully has comparable DAMP measurements: https://treeherder.mozilla.org/#/jobs?repo=try&revision=08362db24890c3021f30b85bb79e351f294b0d03
Reporter | ||
Comment 21•4 years ago
|
||
Reporter | ||
Comment 22•4 years ago
|
||
To try out alternative approaches, I've built a toy version of our React-based console. The goal is to find a way to make the addition of one message fast even after many thousands of messages are already being tracked.
Reporter | ||
Comment 23•4 years ago
|
||
Updated•4 years ago
|
Updated•4 years ago
|
Updated•4 years ago
|
Updated•4 years ago
|
Updated•4 years ago
|
Comment 25•3 years ago
|
||
This will probably be fixed by bug 1753177 too.
Description
•