-
Notifications
You must be signed in to change notification settings - Fork 22.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Issue with "performance.now()": Chrome, Firefox, and Safari are not spec compliant on certain platforms #4713
Comments
Previously, we were combining Date.now() and DOMHighResTimeStamp values to calculate duration. These two value types use different clocks, so we should avoid combining the two value types where possible, since using two different clocks leaves us vulnerable to asymetrical issues. This change also starts running the tests with and without native intersection observer. Previously we were not running tests with native intersection observer. w3c/hr-time#115 mdn/content#4713
Previously, we were combining Date.now() and DOMHighResTimeStamp values to calculate duration. These two value types use different clocks, so we should avoid combining the two value types where possible, since using two different clocks leaves us vulnerable to asymetrical issues. The native intersection observer uses DOMHighResTimeStamp, so we should use that type wherever possible in calculations. This change also removes the native-* files, which are superseded by USE_NATIVE_IO and never part of the public API. Thanks to @xg-wang for pointing out some potential issues affecting one clock and not the other, which could in turn cause asymmetrical bugs: w3c/hr-time#115 mdn/content#4713
Previously, we were combining Date.now() and DOMHighResTimeStamp values to calculate duration. These two value types use different clocks, so we should avoid combining the two value types where possible, since using two different clocks leaves us vulnerable to asymetrical issues. The native intersection observer uses DOMHighResTimeStamp, so we should use that type wherever possible in calculations. This change also removes the native-* files, which are superseded by USE_NATIVE_IO and never part of the public API. Thanks to @xg-wang for pointing out some potential issues affecting one clock and not the other, which could in turn cause asymmetrical bugs: w3c/hr-time#115 mdn/content#4713
Previously, we were combining Date.now() and DOMHighResTimeStamp values to calculate duration. These two value types use different clocks, so we should avoid combining the two value types where possible, since using two different clocks leaves us vulnerable to asymetrical issues. The native intersection observer uses DOMHighResTimeStamp, so we should use that type wherever possible in calculations. This change also removes the native-* files, which are superseded by USE_NATIVE_IO and never part of the public API. Thanks to @xg-wang for pointing out some potential issues affecting one clock and not the other, which could in turn cause asymmetrical bugs: w3c/hr-time#115 mdn/content#4713
Previously, we were combining Date.now() and DOMHighResTimeStamp values to calculate duration. These two value types use different clocks, so we should avoid combining the two value types where possible, since using two different clocks leaves us vulnerable to asymetrical issues. The native intersection observer uses DOMHighResTimeStamp, so we should use that type wherever possible in calculations. This change also removes the native-* files, which are superseded by USE_NATIVE_IO and never part of the public API. Thanks to @xg-wang for pointing out some potential issues affecting one clock and not the other, which could in turn cause asymmetrical bugs: w3c/hr-time#115 mdn/content#4713
Previously, we were combining Date.now() and DOMHighResTimeStamp values to calculate duration. These two value types use different clocks, so we should avoid combining the two value types where possible, since using two different clocks leaves us vulnerable to asymetrical issues. The native intersection observer uses DOMHighResTimeStamp, so we should use that type wherever possible in calculations. This change also removes the native-* files, which are superseded by USE_NATIVE_IO and never part of the public API. Thanks to @xg-wang for pointing out some potential issues affecting one clock and not the other, which could in turn cause asymmetrical bugs: w3c/hr-time#115 mdn/content#4713
Previously, we were combining Date.now() and DOMHighResTimeStamp values to calculate duration. These two value types use different clocks, so we should avoid combining the two value types where possible, since using two different clocks leaves us vulnerable to asymetrical issues. The native intersection observer uses DOMHighResTimeStamp, so we should use that type wherever possible in calculations. This change also removes the native-* files, which are superseded by USE_NATIVE_IO and never part of the public API. Thanks to @xg-wang for pointing out some potential issues affecting one clock and not the other, which could in turn cause asymmetrical bugs: w3c/hr-time#115 mdn/content#4713
Previously, we were combining Date.now() and DOMHighResTimeStamp values to calculate duration. These two value types use different clocks, so we should avoid combining the two value types where possible, since using two different clocks leaves us vulnerable to asymetrical issues. The native intersection observer uses DOMHighResTimeStamp, so we should use that type wherever possible in calculations. This change also removes the native-* files, which are superseded by USE_NATIVE_IO and never part of the public API. Thanks to @xg-wang for pointing out some potential issues affecting one clock and not the other, which could in turn cause asymmetrical bugs: w3c/hr-time#115 mdn/content#4713
Previously, we were combining Date.now() and DOMHighResTimeStamp values to calculate duration. These two value types use different clocks, so we should avoid combining the two value types where possible, since using two different clocks leaves us vulnerable to asymetrical issues. The native intersection observer uses DOMHighResTimeStamp, so we should use that type wherever possible in calculations. This change also removes the native-* files, which are superseded by USE_NATIVE_IO and never part of the public API. Thanks to @xg-wang for pointing out some potential issues affecting one clock and not the other, which could in turn cause asymmetrical bugs: w3c/hr-time#115 mdn/content#4713
Previously, we were combining Date.now() and DOMHighResTimeStamp values to calculate duration. These two value types use different clocks, so we should avoid combining the two value types where possible, since using two different clocks leaves us vulnerable to asymetrical issues. The native intersection observer uses DOMHighResTimeStamp, so we should use that type wherever possible in calculations. This change also removes the native-* files, which are superseded by USE_NATIVE_IO and never part of the public API. Thanks to @xg-wang for pointing out some potential issues affecting one clock and not the other, which could in turn cause asymmetrical bugs: w3c/hr-time#115 mdn/content#4713
Previously, we were combining Date.now() and DOMHighResTimeStamp values to calculate duration. These two value types use different clocks, so we should avoid combining the two value types where possible, since using two different clocks leaves us vulnerable to asymetrical issues. The native intersection observer uses DOMHighResTimeStamp, so we should use that type wherever possible in calculations. This change also removes the native-* files, which are superseded by USE_NATIVE_IO and never part of the public API. Thanks to @xg-wang for pointing out some potential issues affecting one clock and not the other, which could in turn cause asymmetrical bugs: w3c/hr-time#115 mdn/content#4713
Based on mdn/content#4713, change Tracker so it uses performance.timeOrigin + performance.now() for absolute time where available, falling back to navigationStart + performance.now() where available, or Date#getTime where necessary. Browsers may still have bugs in how their clocks behave while frozen but this code is the best approach possible at the moment.
Thanks for the detailed write up, I will look into updating the page. Note to self: Another thing to mention on the performance.now page: coarsening based on cross-origin isolation status per https://chromestatus.com/feature/6497206758539264 |
I've opened #25107. A while ago I also improved the @jonathanmayer would you mind taking a look and let me know if these updates are sufficient enough? Would be happy to work with you on more updates if needed. |
I've now also added a guide page at https://developer.mozilla.org/en-US/docs/Web/API/Performance_API/High_precision_timing Would appreciate a review on that one, too, @jonathanmayer. (This issue will probably be closed if there is no further response) |
I'm going to close this assuming it's fixed :) |
MDN URL: https://developer.mozilla.org/en-US/docs/Web/API/Performance/now
I've edited this issue a number of times, because monotonic timing in browsers is a deep rabbit hole of standards, implementations, operating system clock APIs, and clock hardware (see w3c/hr-time#115). The material below attempts to accurately and concisely document current browser behavior.
What information was incorrect, unhelpful, or incomplete?
There are several components of the documentation that are outdated or incomplete.
High Resolution Time vs. High Resolution Time Level 2
The semantics of
performance.now()
changed from the original High Resolution Time spec to the Level 2 spec. In the original spec,performance.now()
was relative toperformance.timing.navigationStart
from the Navigation Timing spec. In the Level 2 spec,performance.now()
is relative toperformance.timeOrigin
, which is defined in the spec.There are two key differences between these reference times.
navigationStart
andtimeOrigin
are a little different.navigationStart
timestamps a document fetch or an unload prompt (if any), whiletimeOrigin
timestamps creation of the browsing context (if no prior document), an unload prompt (if any), or the start of navigation (as defined by the HTML spec, which is a few steps before fetch).navigationStart
is set with the system clock, which might not be monotonic and might not be consistent across navigation events.timeOrigin
, by contrast, is set with a shared monotonic clock that is defined to be monotonic, consistent across globals, and initially synced to the system clock (e.g., on browser startup). These properties means that comparing timestamps across webpages with the original spec (performance.timing.navigationStart + performance.now()
) has clock change risks, while comparing timestamps across webpages with the Level 2 spec (performance.timeOrigin + performance.now()
) doesn't have clock change risks.Ticking During Sleep
The original High Resolution Time spec does not address whether
performance.now()
should tick during sleep. There was consensus for the Level 2 spec thatperformance.now()
should tick during sleep (see w3c/hr-time#65), but the text of the spec is somewhat ambiguous about sleep behavior and whether that's a normative requirement (see w3c/hr-time#115).Here's a summary table of how browsers appear to currently handle sleep, where ✅ means
performance.now()
keeps ticking and 🚫 means it doesn't.performance.timeOrigin in Chrome and Firefox
There is currently a bug in Chrome where
performance.timeOrigin
is set for each global with the system clock rather than a shared monotonic clock. As a result, comparing High Resolution Time Level 2 timestamps across webpages in Chrome has clock change risks.There is also currently a bug in Firefox where
performance.timeOrigin
is set with a monotonic clock that is synced to the system clock once per process, rather than with a shared monotonic clock that is synced to the system clock once on browser startup. The result is the same: comparing High Resolution Time Level 2 timestamps across webpages in Firefox has clock change risks.Clock Drift on macOS
The current macOS implementation of
performance.now()
in Chrome/Chromium, Firefox, and Safari/WebKit uses a monotonic clock that does not allow for even small, monotonic adjustments (e.g., NTP oscillator corrections). The result can be clock drift between the system clock and High Resolution Time monotonic clocks. Chrome has a bug open on this issue.Specific section or headline?
This content probably belongs in the general description of
performance.now()
because of the significant consequences. Components might also belong on theperformance.timeOrigin
andDOMHighResTimeStamp
pages.What did you expect to see?
performance.timing.navigationStart
). The page should probably include a description for both versions of the spec, examples for both versions of the spec, and an explanation of how the two versions differ, since the changes are subtle and Safari/WebKit hasn't implemented Level 2 yet.performance.timeOrigin
bugs, and what those could mean for use cases.performance.now()
, it has implemented the original High Resolution Time semantics and not the High Resolution Time Level 2 semantics.Did you test this? If so, how?
I've confirmed the following behaviors with both testing and code review:
MDN Content page report details
en-us/web/api/performance/now
The text was updated successfully, but these errors were encountered: