Closed
Bug 1378586
Opened 7 years ago
Closed 7 years ago
clamp setInterval() based on "nesting level" similar to setTimeout()
Categories
(Core :: DOM: Core & HTML, enhancement, P2)
Core
DOM: Core & HTML
Tracking
()
RESOLVED
FIXED
mozilla56
Tracking | Status | |
---|---|---|
firefox56 | --- | fixed |
People
(Reporter: bkelly, Assigned: bkelly)
References
Details
(Keywords: dev-doc-complete)
Attachments
(6 files)
1.84 KB,
patch
|
farre
:
review+
|
Details | Diff | Splinter Review |
3.32 KB,
patch
|
farre
:
review+
|
Details | Diff | Splinter Review |
4.77 KB,
patch
|
farre
:
review+
|
Details | Diff | Splinter Review |
1.04 KB,
patch
|
farre
:
review+
|
Details | Diff | Splinter Review |
1.21 KB,
patch
|
farre
:
review+
|
Details | Diff | Splinter Review |
4.70 KB,
patch
|
farre
:
review+
|
Details | Diff | Splinter Review |
Currently we clamp our DOM timeouts to 4ms in two cases:
1. setInterval() is called
2. A nested setTimeout() is called where the nesting level is at least a certain depth.
This means these two snippets are not equivalent:
// clamps to 4ms immediately
setInterval(f, 0);
// executes four 0ms delay callbacks and then clamps to 4ms
function cb() { f(); setTimeout(cb, 0); }
setTimeout(cb, 0);
In other browsers the clamping is applied after the "nesting level" limit is reached. In chrome its on the 5th callback. In edge it seems to be the 3rd callback.
It would be nice to switch to simply using the "nesting level" even for setInterval(). It would bring us more in line with other browsers and would also let us delete some code. Its possible it might also help a bit on the MrPotatoGun site in bug 1378149.
Assignee | ||
Comment 1•7 years ago
|
||
Safari seems to clamp setInterval() on the 5th or 6th callback.
Comment 2•7 years ago
|
||
That would more closely align with the spec too, though of course the spec allows all this stuff to be arbitrarily delayed. Still, https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#timer-initialisation-steps doesn't use the "repeat" boolean in determining the "timeout" value; it just uses the nesting level.
Updated•7 years ago
|
Priority: -- → P2
Assignee | ||
Comment 3•7 years ago
|
||
Assignee | ||
Comment 4•7 years ago
|
||
Assignee | ||
Comment 5•7 years ago
|
||
Assignee | ||
Comment 6•7 years ago
|
||
Assignee | ||
Comment 7•7 years ago
|
||
Assignee | ||
Comment 8•7 years ago
|
||
Assignee | ||
Comment 9•7 years ago
|
||
Comment on attachment 8885905 [details] [diff] [review]
P1 Track the nesting level on interval Timeout objects. r=farre
This patch makes us update mNestingLevel member on setInterval() Timeout objects. Previously it was not set and it was not updated.
Attachment #8885905 -
Flags: review?(afarre)
Assignee | ||
Comment 10•7 years ago
|
||
Comment on attachment 8885906 [details] [diff] [review]
P2 Avoid Timeout mNestingLevel rollover by just limiting the value to the values we care about. r=farre
While the uint32_t would only roll over once every ~49 days, lets just avoid that situation. This patch caps the mNestingLevel at the value we care about. There isn't really any point incrementing beyond the threshold.
This also lets us shrink the mNestingLevel field to a uint8_t.
Attachment #8885906 -
Flags: review?(afarre)
Assignee | ||
Comment 11•7 years ago
|
||
Comment on attachment 8885907 [details] [diff] [review]
P3 Reorder Timeout members to improve binary packing. No functional change. r=farre
A bit unrelated to this bug, but to take advantage of the mNestingLevel shrinking to a uint8_t, lets reorder the Timeout members to get better packing. This reduces the size of Timeout from 104 to 96 in opt builds. This is just enough to get in the next lower bucket in jemalloc.
Attachment #8885907 -
Flags: review?(afarre)
Assignee | ||
Comment 12•7 years ago
|
||
Comment on attachment 8885908 [details] [diff] [review]
P4 Clamp setInterval() based on nesting value instead of always. r=farre
Stop considering the mIsInterval member when deciding whether to clamp or not. Just look at mNestingLevel.
Attachment #8885908 -
Flags: review?(afarre)
Assignee | ||
Comment 13•7 years ago
|
||
Comment on attachment 8886198 [details] [diff] [review]
P5 Don't force setInterval() to a min 1ms delay. r=farre
We also used to limit setInterval() delays to a minimum of 1ms. Apparently we used a 0ms delay as a signal somewhere in the code in the distant past. AFAICT, though, we no longer do this. We use mIsInterval instead now.
Stop forcing a minimum 1ms delay on setInterval.
Attachment #8886198 -
Flags: review?(afarre)
Comment 14•7 years ago
|
||
Ben, is it ok if I get to this Monday/Tuesday next week? I'm on pto this week.
Flags: needinfo?(bkelly)
Assignee | ||
Comment 15•7 years ago
|
||
(In reply to Andreas Farre [:farre] from comment #14)
> Ben, is it ok if I get to this Monday/Tuesday next week? I'm on pto this
> week.
Yea, I didn't expect a response this week. I'm going on PTO tomorrow, so just filing before I leave.
Flags: needinfo?(bkelly)
Updated•7 years ago
|
Attachment #8885905 -
Flags: review?(afarre) → review+
Updated•7 years ago
|
Attachment #8885906 -
Flags: review?(afarre) → review+
Updated•7 years ago
|
Attachment #8885907 -
Flags: review?(afarre) → review+
Updated•7 years ago
|
Attachment #8885908 -
Flags: review?(afarre) → review+
Updated•7 years ago
|
Attachment #8886198 -
Flags: review?(afarre) → review+
Updated•7 years ago
|
Keywords: dev-doc-needed
Assignee | ||
Comment 16•7 years ago
|
||
I think I should write a test before landing this.
Assignee | ||
Comment 17•7 years ago
|
||
This test attempts to verify we start clamping in both setTimeout() chains and setInterval() at the same iteration. In addition, it tries to verify that we continue clamping for iterations after that.
I verified the setInterval() test steps fail without the other patches in this bug.
Note, this will be somewhat timing dependent. I increased the clamp time pref to try to offset that. I also preemptively disabled the test on android debug since its an agonizingly slow platform and would probably have intermittent failures.
https://treeherder.mozilla.org/#/jobs?repo=try&revision=f7168ff42bb0c468d69e1f3fb762f6eed0578df8
Attachment #8889612 -
Flags: review?(afarre)
Updated•7 years ago
|
Attachment #8889612 -
Flags: review?(afarre) → review+
Comment 18•7 years ago
|
||
Pushed by bkelly@mozilla.com:
https://hg.mozilla.org/integration/mozilla-inbound/rev/ef429397347b
P1 Track the nesting level on interval Timeout objects. r=farre
https://hg.mozilla.org/integration/mozilla-inbound/rev/adc6dc3c8c4e
P2 Avoid Timeout mNestingLevel rollover by just limiting the value to the values we care about. r=farre
https://hg.mozilla.org/integration/mozilla-inbound/rev/9d1d8507fc97
P3 Reorder Timeout members to improve binary packing. No functional change. r=farre
https://hg.mozilla.org/integration/mozilla-inbound/rev/fbccc5bd7c14
P4 Clamp setInterval() based on nesting value instead of always. r=farre
https://hg.mozilla.org/integration/mozilla-inbound/rev/81c36a4d6b36
P5 Don't force setInterval() to a min 1ms delay. r=farre
https://hg.mozilla.org/integration/mozilla-inbound/rev/bb9485e6290b
P6 Add a mochitest that verifies timeout clamping behavior. r=farre
Comment 19•7 years ago
|
||
bugherder |
https://hg.mozilla.org/mozilla-central/rev/ef429397347b
https://hg.mozilla.org/mozilla-central/rev/adc6dc3c8c4e
https://hg.mozilla.org/mozilla-central/rev/9d1d8507fc97
https://hg.mozilla.org/mozilla-central/rev/fbccc5bd7c14
https://hg.mozilla.org/mozilla-central/rev/81c36a4d6b36
https://hg.mozilla.org/mozilla-central/rev/bb9485e6290b
Status: ASSIGNED → RESOLVED
Closed: 7 years ago
status-firefox56:
--- → fixed
Resolution: --- → FIXED
Target Milestone: --- → mozilla56
Comment 20•7 years ago
|
||
I've had a go at documenting this, although you might want to check the description. I first updated the description of the behaviour on the setTimeout() page:
https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#Timeouts_throttled_to_%3E4ms
I also added a note to the Fx56 rel notes:
https://developer.mozilla.org/en-US/Firefox/Releases/56#DOM
Let me know if more work needs to be done on this. Thanks!
Flags: needinfo?(bkelly)
Keywords: dev-doc-needed → dev-doc-complete
Assignee | ||
Comment 21•7 years ago
|
||
Chris, that looks good! The only comment I have is its unclear to me if chrome/safari/edge ever clamped immediately on setInterval() or if they always did what they do today (and what we just implemented). If you wanted you could rearrange it a bit to say browsers clamp after their given number of iterations whether via setTimeout() chaining or setInterval(). In the past some browsers clamped immediately on setInterval(); for example Firefox 55 and earlier.
But I'm not sure that nuance is really necessary or not.
Thanks!
Flags: needinfo?(bkelly)
Comment 22•7 years ago
|
||
(In reply to Ben Kelly [:bkelly] from comment #21)
> Chris, that looks good! The only comment I have is its unclear to me if
> chrome/safari/edge ever clamped immediately on setInterval() or if they
> always did what they do today (and what we just implemented). If you wanted
> you could rearrange it a bit to say browsers clamp after their given number
> of iterations whether via setTimeout() chaining or setInterval(). In the
> past some browsers clamped immediately on setInterval(); for example Firefox
> 55 and earlier.
>
> But I'm not sure that nuance is really necessary or not.
>
> Thanks!
I *think* I understand this ;-)
Is the update any better:
https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#Timeouts_throttled_to_%3E4ms
?
Flags: needinfo?(bkelly)
Assignee | ||
Comment 23•7 years ago
|
||
(In reply to Chris Mills (Mozilla, MDN editor) [:cmills] from comment #22)
> I *think* I understand this ;-)
>
> Is the update any better:
>
> https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/
> setTimeout#Timeouts_throttled_to_%3E4ms
>
> ?
I think the current location of this text is wrong/confusing now: "Gecko acquired this behaviour in version 56." We only really changed setInterval() in that version.
Also, to really nitpick I think the text here is a bit confusing:
"Gecko clamps on the 4th call"
Does "call" there mean the call to setTimeout() or the call to the callback? In old versions of the text it might have meant setTimeout(), but that doesn't make as much sense now that we are including setInterval() here. setInterval() is only called once.
This only really matters if we want the number to be exactly accurate, though. This test shows that we clamp on the 5th callback:
http://searchfox.org/mozilla-central/source/dom/base/test/test_timeout_clamp.html
I converted this into a glitch snippet here:
https://timeout-clamp.glitch.me/
It shows that both firefox and chrome start clamping on the 5th callback currently.
Safari seems to clamp on the 6th callback.
Edge seems to introduce more delay now and often has 4ms or more delay on the first callback. Sometimes, though, it shows that the first 4ms callback comes much, much later (11th callback, etc). I'm not sure this is strictly clamping. I think this might be more timeout coalescing to improve battery time.
Flags: needinfo?(bkelly)
Assignee | ||
Comment 24•7 years ago
|
||
At the end of the day, this stuff is likely to keep changing. As can be seen by edge, browser vendors are pushing timeouts to try to improve battery efficiency. Sites should really not depend on timeouts less than 4ms in length in general.
Comment 25•7 years ago
|
||
(In reply to Ben Kelly [:bkelly] from comment #24)
> At the end of the day, this stuff is likely to keep changing. As can be
> seen by edge, browser vendors are pushing timeouts to try to improve battery
> efficiency. Sites should really not depend on timeouts less than 4ms in
> length in general.
Thanks Ben. I've made one more set of changes to get rid of the confusion you cited above. I think I'll leave it be for now and we'll see what happens in the future.
Updated•6 years ago
|
Component: DOM → DOM: Core & HTML
You need to log in
before you can comment on or make changes to this bug.
Description
•