Open
Bug 1308660
Opened 8 years ago
Updated 2 years ago
for background tabs, break refresh driver tick into multiple events off the main thread's event loop
Categories
(Core :: Layout, enhancement)
Core
Layout
Tracking
()
People
(Reporter: dbaron, Assigned: smaug, NeedInfo)
References
(Blocks 2 open bugs)
Details
(Keywords: perf, perf:responsiveness)
Attachments
(1 file)
4.32 KB,
patch
|
Details | Diff | Splinter Review |
A few weeks ago I was discussing with smaug the problem of background tabs sometimes hogging the main event loop for an extended period of time, sometimes in layout. Since we're running refresh ticks in background tabs quite infrequently (1 second, I think), a decent amount of work can accumulate by the time we get around to ticking the refresh driver, particularly during page loading. One thing that occurred to me is that, for background tabs, we don't need to run the entire refresh tick in a single event off the main event lop. Instead, we could split it up to run in multiple events off the main event loop, to reduce the amount of time that it keeps us away from the event loop. There are two different approaches to the splitting of work for a single page: Approach A would be something roughly like: - on event 1, run everything through content flushing - on event 2, run everything through style flushing / frame construction - on event 3, run everything through reflow That is, later events would "duplicate" the work of the earlier ones, but hopefully there wouldn't be anything or much accumulated to do. Approach B would actually be to split up the refresh driver tick without duplication. This *might* require that we ensure nothing else from the page happens in between, which we don't currently have the ability to do, but which is being worked on. This would make it safer to do finer-grained splitting (which I'll file an additional bug on some ideas for). Additionally, we should also be more aggressive about splitting up the work between a parent document and its subdocuments. I *believe* these currently share the same refresh driver, which I means we're currently running the refresh tick for all these subdocuments on a single event off of the main thread. We should instead separate these to different main thread events, with ancestor documents before descendant documents (since flushing in a descendant can cause flushing in an ancestor).
Comment 1•8 years ago
|
||
> I *believe* these currently share the same refresh driver
Do all background tabs also share a single refresh driver? And if so, should we break these up too, presumably?
Reporter | ||
Comment 2•8 years ago
|
||
I don't think so, based on a quick reading of nsPresContext::Init. I was just saying that parent documents and their subdocuments (iframes) share the same refresh driver.
Updated•7 years ago
|
Blocks: QuantumFlow
Comment 3•7 years ago
|
||
Too late for firefox 52, mass-wontfix.
Updated•7 years ago
|
Whiteboard: [qf]
Updated•7 years ago
|
Whiteboard: [qf] → [qf:p1]
Comment 4•7 years ago
|
||
A RefreshDriver overhaul like described here is a multi-month job. I've seen other risky background tab optimization requests pop up with qf:p1 designations. Layout team is focused on the front tab for Quantum Flow.
Whiteboard: [qf:p1] → [qf]
Assignee | ||
Comment 6•7 years ago
|
||
In theory we could preempt between different phases of a tick, I think.
Comment 7•7 years ago
|
||
(In reply to Naveed Ihsanullah [:naveed] from comment #5) > Will our work on Quantum DOM makes this issue less? I think this is what dbaron means is a prerequisite for what he calls Approach B above. Can Quantum DOM guarantee that content won't need to flush again on a subsequent tick when Layout flushes?
Flags: needinfo?(bugs)
Assignee | ||
Comment 8•7 years ago
|
||
If preemption gets implemented properly, we should be able to guarantee flush isn't needed. But to be more precise, this wouldn't be about all background tabs, but background tabs in a certain tabgroup. If say foreground tab A and a background tab B share the tabgroup, QDOM can't help here (assuming foreground tab is kept running all the time).
Comment 9•7 years ago
|
||
How about pursuing approach A? It seems not too hard to do. Is the risk of duplicating work too bad in practice?
Assignee | ||
Comment 10•7 years ago
|
||
I was looking for a testcase for this (since reflow is usually by far the slowest part here) and looks like loading single page HTML spec in background works as such. I can see processing pending styles taking 25% of ticks, reflow 75%. And yes, A at least doesn't sound too hard to do. In fact it sounds like simple enough that we could try it to see how it works or whether it creates some issues.
Assignee | ||
Comment 11•7 years ago
|
||
I think splitting the work to two is probably enough, first event does style flush, second style+layout.
Assignee | ||
Comment 12•7 years ago
|
||
Hmm, animation events and such might broke easily with A.
Assignee | ||
Comment 13•7 years ago
|
||
Or maybe it could be something as simple as this, since styles can be flushed anyhow before dispatching any events. So animation events etc. will be dispatched when doing the real tick. This drops % style flushing takes during RefreshDriver::Tick from 25% to 4% in the "single page HTML spec in background" case, so the actual Tick becomes almost only reflow and style flushing happens async beforehand.
Assignee | ||
Comment 14•7 years ago
|
||
https://treeherder.mozilla.org/#/jobs?repo=try&revision=5952618d0bc9b1c18a95bde5b331993bb8642666
Assignee | ||
Comment 15•7 years ago
|
||
Without the patch first tick with single page HTML spec takes ~740ms and with the patch ~560ms (and time is spent async before tick doing style flush). Profiler reports about the same delay for event processing, but I guess that depends on how it is measured, since clearly if some work is split to two pieces, other runnables may be processed between them.
Assignee | ||
Comment 16•7 years ago
|
||
Comment on attachment 8863220 [details] [diff] [review] quick patch for testing dbaron, what you think of this kind of super simple approach?
Attachment #8863220 -
Flags: feedback?(dbaron)
Updated•7 years ago
|
Whiteboard: [qf] → [qf:p1]
Assignee | ||
Comment 17•7 years ago
|
||
And the patch works the way it does, and not doing reflow-less-but-otherwise-normal-tick first and then reflow only tick, since it isn't clear how nsARefreshObservers would work in that kind of setup.
Updated•7 years ago
|
Blocks: qf-bugs-upforgrabs
Reporter | ||
Comment 18•7 years ago
|
||
Comment on attachment 8863220 [details] [diff] [review] quick patch for testing So I'm not happy about the code duplication -- I worry we'll pile more stuff on top and then be unable to unduplicate. I'd much rather start with splitting up of the refresh driver's tick method. I'm fine with starting off with splitting out a "restyling part", and then trying to do some ticks that just do the restyling part and some ticks (nearly immediately after) that do (I guess) everything, including flushing a hopefully-empty restyle queue. Maybe we (dbaron, smaug, bz) should sit down this week to talk. (Also, I still have no idea what to do with a feedback?, so just clearing it.)
Attachment #8863220 -
Flags: feedback?(dbaron)
Reporter | ||
Updated•7 years ago
|
Flags: needinfo?(dbaron)
Assignee | ||
Comment 19•7 years ago
|
||
Yeah, I could have a helper method to go through style observers. I'll prepare a patch for that.
Updated•7 years ago
|
Assignee: nobody → bugs
Updated•7 years ago
|
Whiteboard: [qf:p2] → [qf:p3]
Assignee | ||
Comment 21•7 years ago
|
||
I reconsidered this. I think this should be p1. Creating frames is slow, and then we do also slow reflow, so better to try to do that all in two or more steps when dealing with background tabs.
Whiteboard: [qf:p3] → [qf:p1]
Updated•7 years ago
|
Whiteboard: [qf:p1] → [qf:i60][qf:p1]
Updated•7 years ago
|
Whiteboard: [qf:i60][qf:p1] → [qf:f60][qf:p1]
Updated•6 years ago
|
Whiteboard: [qf:f60][qf:p1] → [qf:f61][qf:p1]
Comment 22•6 years ago
|
||
smaug, would this still be useful in a more-e10s world?
Flags: needinfo?(bugs)
Assignee | ||
Comment 23•6 years ago
|
||
Yes, this or the variant where we don't run refreshdriver at all in the background.
Flags: needinfo?(bugs)
Assignee | ||
Comment 24•6 years ago
|
||
...because styling and reflow are after all rather slow, and quite often several tabs will be in the same docgroup even in more-e10s world.
Updated•6 years ago
|
Whiteboard: [qf:f61][qf:p1] → [qf:f64][qf:p3]
Updated•6 years ago
|
Whiteboard: [qf:f64][qf:p3] → [qf:p3:f64]
Updated•6 years ago
|
Whiteboard: [qf:p3:f64] → [qf:p3]
Comment 25•5 years ago
|
||
This should probably be retriaged by the qf triage group, and categorized.
Whiteboard: [qf:p3] → [qf]
Updated•5 years ago
|
No longer blocks: qf-bugs-upforgrabs
Assignee | ||
Comment 26•5 years ago
|
||
This should be qf:responsiveness:p<x> .
Possibly because of Fission this will become more important if user has tabs using same process.
One thing we should probably do here is to wait for 1s and then post a runnable to the idle queue to ensure we less likely run
RefreshDriver in background tabs when there is something more important happening.
Whiteboard: [qf] → [qf?]
Updated•5 years ago
|
Whiteboard: [qf?] → [qf]
Assignee | ||
Updated•5 years ago
|
Whiteboard: [qf] → [qf:p3:responsiveness]
Updated•2 years ago
|
Comment hidden (off-topic) |
Comment 28•2 years ago
|
||
Sorry, there was a problem with the detection of inactive users. I'm reverting the change.
Assignee: nobody → smaug
Updated•2 years ago
|
Severity: normal → S3
Updated•2 years ago
|
Severity: S3 → --
Type: defect → enhancement
You need to log in
before you can comment on or make changes to this bug.
Description
•