make setTimeout() low priority during page load
Categories
(Core :: Performance, defect)
Tracking
()
People
(Reporter: cynthiatang, Assigned: jesup)
References
(Depends on 2 open bugs, Regressed 4 open bugs)
Details
(Keywords: perf, perf:pageload, site-compat)
Attachments
(3 files, 13 obsolete files)
54.06 KB,
patch
|
smaug
:
review+
|
Details | Diff | Splinter Review |
2.09 KB,
patch
|
smaug
:
review+
|
Details | Diff | Splinter Review |
2.18 KB,
patch
|
davehunt
:
review+
jmaher
:
review+
|
Details | Diff | Splinter Review |
Comment 1•9 years ago
|
||
![]() |
||
Updated•9 years ago
|
Comment 2•7 years ago
|
||
Comment 3•7 years ago
|
||
Assignee | ||
Updated•6 years ago
|
Updated•6 years ago
|
Assignee | ||
Comment 5•6 years ago
|
||
Assignee | ||
Updated•6 years ago
|
Assignee | ||
Comment 6•6 years ago
|
||
The general algorithm here (not written in stone - more like in putty) is to push content setTimeouts/Intervals to a list processed off the Idle queue during pageload. On end of pageload we move them all back to the 'normal' queue. (Note that a Reschedule on that is probably still missing from the patch.)
Chrome does something similar in their scheduling; they push all timers to a different queue which they deprioritize during load. Overall there's a bunch of complexity around this in chrome, which I'm investigating for ideas. They will run timeouts during mainthred-idle periods.
We could use a new idle queue with different parameters. We could handle relative timeouts differently than in this patch...
Assignee | ||
Comment 7•6 years ago
|
||
Comment 8•6 years ago
|
||
Assignee | ||
Comment 9•6 years ago
|
||
Assignee | ||
Updated•6 years ago
|
Assignee | ||
Comment 10•6 years ago
|
||
It's definitely deferring most timeouts now; for facebook typically it doesn't run them until ~load -- or iframe load, I'm checking on that. Nationalgeographic has some idle time, so lots of timeouts run before load.
https://faraday.basschouten.com/mozilla/executionorder/externaltimeout0.html now paints a waffle (in low-resolution....) before running the timeout! But a second run fired Load and released the timeout before we painted, so we'll want to think if there's any adjustment we want to do (small delay after load, or trigger off something later in the pipeline, or leave it). https://perfht.ml/2TXti2z -- in the marker chart under settimeout, you can see that it deferred the timer by 7ms (and ran it from the idle callback) detail: https://perfht.ml/2TYsA54 Second run: https://perfht.ml/2U1kDMO
Loading buzzfeed shows that no timeouts ran off the idle queue (no idle time) -- however, there are a bunch of settimeout release markers, mostly before the final load event, which implies to me that they're due to loads of iframes and their timeouts are being released before the document load: https://perfht.ml/2TYtSwW So it may need additional work on where the load signal comes from.
There are separate markers for setTimeout -- deferred and ran off idle queue -- and setTimeout release -- moved back to head of normal queue after isLoading moves to false (with a MaybeSchedule pass to reset wait time if needed). I'll tweak the markers to make it easier to compare, as well as add a pref to flip this on and off
It builds clean across the board, though tp6 had some sort of problem - https://treeherder.mozilla.org/#/jobs?repo=try&author=rjesup%40wgate.com&selectedJob=222662253
Comment 11•6 years ago
|
||
Assignee | ||
Comment 12•6 years ago
|
||
Assignee | ||
Updated•6 years ago
|
Assignee | ||
Comment 13•6 years ago
|
||
Assignee | ||
Updated•6 years ago
|
Assignee | ||
Updated•6 years ago
|
Assignee | ||
Comment 14•6 years ago
|
||
Assignee | ||
Updated•6 years ago
|
Comment 15•6 years ago
|
||
One thing need to be careful at is that if page loading takes forever, as it may, we probably don't want to slow down timers too long time.
And, need to ensure timers get still run before idle queue, since browser uses idle queue for several heavy operations, like GC and CC and object deletion.
As we discussed on IRC, perhaps we could add a new queue to the main thread, something which gets handled after normal priority queue but before idle queue..
Assignee | ||
Comment 16•6 years ago
|
||
Well, even when it does take forever, the timeouts will still run off idle time on mainthread - but they may be delayed more than normal. We could put a max time of say 60 or 120 seconds on the delaying period, or perhaps variable based on <something> - bandwidth, device type (mobile vs desktop), activity, etc. We could also put a max time on how long a timeout will be delayed, though I'm less in love with that idea.
And yes, we should get this ahead of generic idle queue users.
Assignee | ||
Comment 17•6 years ago
|
||
Assignee | ||
Updated•6 years ago
|
Assignee | ||
Comment 18•6 years ago
|
||
Nathan, bz - a ping for your feedback on the approach here. The general idea is to address some of the issues around scheduling during a load, in particular scheduling of setTimeout calls - we've found that part of the difference between us and chrome is that often sites (or ads on sites) schedule a lot of timeouts that we fire before the load finishes - and chrome fires after it finishes (or much later in the load sequence, after all the important parts of the page have rendered). Chrome purposely deprioritizes timeouts during load. From a webcompat point-of-view, we're not required to run them at any particular time (witness what we do with background tabs, etc).
When they run before load, they not only can be long, but they can also start loads of more resources which end up blocking the load event (since they end up in the loadgroup). I've also toyed with making resources loaded from timeouts to be put in a separate loadgroup, so they don't block load from firing. That generally wouldn't affect the appearance of the page in most cases (except where the load event itself does), but we'd turn off the throbber earlier and metrics would show the page as loaded earlier. There's justification (if not compliant with the spec) in that the timeout could have run after the load event, and if so the resources wouldn't have blocked the load event.
I have not done anything along these lines so far; this bug is all about deferring timeouts during load, and only running them when we process the idle queue. (We'll probably run timeouts ahead of any other idle runnables, like CC, etc, but the patch doesn't do this yet).
Thanks for any feedback, or thoughts on heuristics here. (For example, we could be more aggressive at running settimeout's for 0 or not defer them at all.)
Comment 19•6 years ago
|
||
Assignee | ||
Comment 20•6 years ago
|
||
- I think the existing idle queue isn't a great place to add timeout
handlers to. Like smaug mentioned in comment 15, there may be other events
in the idle queue before the timeout handlers which can be really expensive
to run, and that is kind of the point of the idle queue.
Agreed, and I said something similar in comment 18. This is a starting point/WIP/proof-of-concept before doing the other corollary patches.
- I think it would be nice if your patch didn't tie the lowering of the
priority of timeouts merely to pageloads. See this document from the Blink
Scheduler docs if you haven't already
<https://docs.google.com/document/d/163ow-
1wjd6L0rAN3V_U6t12eqVkq4mXDDjVaA4OuvCA/edit> (note that it is rather old and
possibly a bit out of date). Blink lowers the priority of timeouts in
several cases, for example during pageload, touch events, scrolling, etc.
Yes; I started working on this patch after investigating Blink's timer behavior (which we could see was different in profiles). Once we have this, we can look at other inputs/controls; right now we just have inputs into the TimeoutManager; it decides how to schedule. We can certainly add more inputs - or move control of that outside of TimeoutManager as you suggest; that's largely a detail of where we want the scheduling control to live.
Thanks a lot for doing this work, I think the positive impact of this would
be something users would appreciate!
:-) thanks
![]() |
||
Comment 21•6 years ago
|
||
![]() |
||
Updated•6 years ago
|
Assignee | ||
Comment 22•6 years ago
|
||
I am not super-excited about the possibility of adding more code to
PrioritizedEventQueue, but I also don't see how to put some of the logic in
SchedulerGroup/TabGroup/DocGroup or similar.
Right; I think it has to live there somehow, and having a single prioritized queue and doing priority inserts doesn't seem like a great idea.
- nsresult MaybeSchedule(RefPtr<TimeoutExecutor>& aExecutor,
const TimeStamp& aWhen,
There's this weird asymmetry in the patch where this function has been
seemingly generalized by taking a TimeoutExecutor, but it's only ever used
with mExecutor, never with the idle executor. I don't think that's a good
idea; afaict, it's wrong to use it with mIdleExecutor. Can we change the
prototype here and/or change the name?
Yeah, originally I had it handling both executors, but I don't want to update the budget for idleexecutor when we call MaybeSchedule. I can undo the API change to that method. Alternatively I could keep passing in the executor, and skip UpdateBudget if it's the idle queue. Or pass a boolean in and let MaybeScedule decide. Or have two MaybeSchedule methods,which imply the queue.
Personally, for now I'm just reverting the API change to MaybeSchedule.
Assignee | ||
Comment 23•6 years ago
|
||
Assignee | ||
Updated•6 years ago
|
Assignee | ||
Updated•6 years ago
|
Comment 25•6 years ago
|
||
Comment 26•6 years ago
|
||
Updated•6 years ago
|
Assignee | ||
Comment 27•6 years ago
|
||
Assignee | ||
Comment 28•6 years ago
|
||
Assignee | ||
Updated•6 years ago
|
Assignee | ||
Comment 29•6 years ago
|
||
Updated•6 years ago
|
Comment 30•6 years ago
|
||
Assignee | ||
Comment 31•6 years ago
|
||
Assignee | ||
Comment 32•6 years ago
|
||
Assignee | ||
Updated•6 years ago
|
Assignee | ||
Updated•6 years ago
|
Updated•6 years ago
|
Updated•6 years ago
|
Assignee | ||
Comment 33•6 years ago
|
||
Assignee | ||
Comment 34•6 years ago
|
||
Updated•6 years ago
|
Assignee | ||
Comment 35•6 years ago
|
||
Green try apparently (some tests still running): https://treeherder.mozilla.org/#/jobs?repo=try&revision=1eed805e2f3f12db0551ac88cb90192c8e6fd9f8
And talos with --rebuild 5: https://treeherder.mozilla.org/#/jobs?repo=try&revision=6d624f892c917f19d4dc432c03a07f1dab994ab7
Assignee | ||
Updated•6 years ago
|
Assignee | ||
Updated•6 years ago
|
Assignee | ||
Comment 36•6 years ago
|
||
Assignee | ||
Updated•6 years ago
|
Comment 37•6 years ago
|
||
Comment 38•6 years ago
|
||
Comment 39•6 years ago
|
||
Comment 40•6 years ago
|
||
Assignee | ||
Comment 41•6 years ago
|
||
jmaher - I'm still getting intermittent oranges on Talos TP6 in
https://hg.mozilla.org/integration/mozilla-inbound/rev/cec0a3a47cdb
It was green on my trys. See: https://treeherder.mozilla.org/#/jobs?repo=try&revision=6d624f892c917f19d4dc432c03a07f1dab994ab7
Thoughts? Just increase the time we wait for the Hero? (perhaps it's another item, not the hero, which wasn't done by load time?) Runs fine locally now.
Comment 42•6 years ago
|
||
Comment 43•6 years ago
|
||
bugherder |
https://hg.mozilla.org/mozilla-central/rev/7f8594d21c51
https://hg.mozilla.org/mozilla-central/rev/eec1a6963a9c
https://hg.mozilla.org/mozilla-central/rev/cec0a3a47cdb
https://hg.mozilla.org/mozilla-central/rev/925fed5e69e7
Comment 44•6 years ago
•
|
||
Randell, fyi
Coverity thinks that a part of the code could be simplified
dead_error_condition: The condition aProcessIdle must be true.
https://searchfox.org/mozilla-central/source/dom/base/TimeoutManager.cpp#924
as we do if (aProcessIdle) {
a few lines above:
https://searchfox.org/mozilla-central/source/dom/base/TimeoutManager.cpp#917
Assignee | ||
Comment 45•6 years ago
|
||
Thanks, I'll add it to some of my cleanup (likely I'll remove the outer if() and add markers for all setTimeouts)
Comment 46•6 years ago
|
||
as discussed on irc- this is only affecting tp6 stylo-threads=1 which is a test we are not planning to run long term on talos, so disabling the test is fine (in this case tp6-google)
Comment 47•6 years ago
|
||
Comment 48•6 years ago
|
||
please create a separate bug for that :)
Assignee | ||
Comment 49•6 years ago
|
||
:jesup, is this hero element change something that you are planning to make
in Raptor also?
Only if we see oranges from it missing the hero; given how raptor works (and that it measures ttfi, which requires more time) I doubt it will.
Updated•6 years ago
|
Comment 50•6 years ago
|
||
Posted site compatibility note: https://www.fxsitecompat.com/en-CA/docs/2019/settimeout-and-setinterval-are-now-deferred-during-page-load/ (Thanks for the heads-up, Ehsan!)
Comment 51•6 years ago
|
||
Can you suggest a release note? Is there going to be any sort of blog post describing this that we can link to?
Updated•6 years ago
|
Updated•6 years ago
|
Updated•3 years ago
|
Description
•