-
Notifications
You must be signed in to change notification settings - Fork 24
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
Suggestions: ticking during sleep, comparison across contexts, time origin + now semantics, and skew definition #115
Comments
Hi, thanks for the feedback!
Your suggestion is just to add more examples of 'scenarios' to explicitly call out sleep, is that right? That seems good to me. I also noticed that the note uses 'should', which is not allowed @yoavweiss. Which is related to the second point below...
That seems fine, although AFAIK implementations haven't changed to behave properly during sleep. I guess this is a good reminder to do so :) I thought we had a bug for this but I couldn't find it so I filed https://bugs.chromium.org/p/chromium/issues/detail?id=1206450 instead, just so we don't keep forgetting. I don't think this will be a trivial change though.
So if I understand correctly, you're saying clock skew is a well defined term and our usage in the spec does not really use it properly? My guess this is indeed trying to say that there should be no adjustments, and perhaps it should say that even monotonic clocks are adjusted but with certain conditions met (like monotonicity is preserved and adjustment sizes are very small). |
Thank you for the valuable spec!
Yep.
Good point. In the prior discussions I've found about High Resolution Time monotonic clocks and sleep, there's been some ambiguity about whether ticking during sleep is normative or informative. A should in an informative note probably contributes to that ambiguity.
I did some digging into the Chrome, Firefox, and Safari codebases to help MDN document implementations: mdn/content#4713. Here's a summary table of what I think current browser behaviors are, where ✅ means High Resolution Time clocks tick during sleep and 🚫 means they don't.
I found a couple relevant Chrome bugs, though neither is quite framed as a spec conformance issue.
A proposal associated with the earlier bug was especially helpful in understanding Chrome's behavior and what would be required for changes: https://docs.google.com/document/d/1Ll-8Nvo6JlhzKEttst8GHWCc7_A8Hluy2fX99cy4Sfg/edit I do think there's a small bug in the proposal, though... confusingly,
Definitely. Let me take another try at formalizing normative semantics for
There are several important properties that follow from these semantics.
The current usage of the term "clock skew" is not consistent with the primary ways that term is used in computer science or electrical/computer engineering. Unfortunately, there's also inconsistency in those fields... sometimes clock skew means the difference in time values between two clocks (that's probably the most common meaning), sometimes clock skew means the difference in frequencies between two clocks (that's how NTP version 3 / RFC 1305 defined the term), and sometimes clock skew means the difference between when clock signals arrive (in circuit design). Looking over the spec again, I would suggest just replacing the term.
That sounds good. I don't believe Linux currently offers a monotonic clock that both ticks during sleep and is not subject to small or gradual monotonic adjustments, so it would be helpful to clarify that those types of adjustments are permitted. |
Since the High Resolution Time API is essentially an abstraction over operating system and hardware clocks, I looked further into what's currently possible on widely deployed platforms. Short version: there is now near-universal support for implementing the semantics above, which wasn't the case when the API was initially designed. That might be a reason to make the semantics above—which are already implicit in the spec—explicit and normative. Long version: here's what I've learned, with the caveats that this isn't an area of expertise and this is a deep rabbit hole. Hardware
Intel has implemented invariant TSC as a standard feature since the Nehalem architecture (~2008), and AMD has supported invariant TSC as a standard feature since the K10 architecture (also ~2008).
Operating Systems
References
|
Thanks all for hearing me out on today's call. Here are the Chrome and Firefox
In short, both browsers depart from the spec in how they set There's another relevant Chrome bug that I didn't touch on during the call. Chrome uses a macOS monotonic clock API that doesn't allow monotonic small/gradual adjustments (e.g., NTP oscillator adjustments or slewing). The choice of clock API appears to be causing a drift between the monotonic clock and the system clock. That behavior is probably unexpected and unwanted for API users, and it probably increases the browser fingerprinting surface. Some additional reasons that normative text about clock adjustments would be valuable. |
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
@yoavweiss, is this actionable at all on the spec level? |
I think this is mostly an implementation issue. @jonathanmayer - is that correct? |
There are specific actionable shortcomings in the specification. These problems contribute to the inconsistencies in implementations. Here's an abbreviated summary. 1. Ticking during system sleep. The specification does not clearly state the consensus about Recommended Revision: State in Section 7 normative text that 2. Ticking when a context is suspended. The specification states a use case of comparing high-resolution timestamps across contexts. Achieving that property necessitates that Recommended Revision: State in Section 7 normative text that 3. Reference point for the shared monotonic clock. The specification contradicts itself. Section 7 requires setting the shared monotonic clock with the ECMA-262 system clock. Section 8, however, says that is only a recommendation. Recommended Revision: Remove the inconsistent clause about ECMA-262 time in Section 8. 4. Clock skew. The term "clock skew" is undefined, ambiguous, inconsistent with what the term usually means (depending on the interpretation), and not testable (because it does not map to particular clock APIs offered by operating systems). Recommended Revision: Remove the term clock skew. Define the term "clock adjustment" to mean 1) manual changes to the system clock or 2) automated changes to the system clock that are either non-monotonic or large (e.g., NTP time jumps). This definition would not include automated changes to the system clock that are monotonic and small (e.g., NTP oscillator adjustments or clock slewing). 5. Shared monotonic clock. The specification is ambiguous about when the clock is "shared" and when it isn't, with a mix of normative and informative description in Section 7. Implementations are inconsistent, in part because of this lack of clarity. The related note in Section 7 also violates W3C style guidance, for the same reason as the other note. Recommended Revision: State in Section 7 normative text that the shared monotonic clock must be shared across all contexts, regardless of implementation (e.g., different processes or threads), and the only circumstances in which the shared monotonic clock may reset are a browser restart, private browsing mode, or different browsing profile. Revise the related note to conform to W3C style guidance. 6. Comparison between high-performance timestamps and ordinary timestamps. Many implementers are confused about how Recommended Revision: State in informative text that |
A comment at the end of hr-time mdn#115 summarized the issue well so I thought it might be more helpful to link directly to it. The top of the issue has more to do with getting others on the same page re: the exact details of this issue. Ref: w3c/hr-time#115 Ref: mdn#33760
Hi all,
My research group at Princeton has been collaborating with Mozilla on a project that involves precise monotonic cross-context timing. We've encountered a recurring browser- and platform-specific implementation issue, where a context's High Resolution Time monotonic clock does not tick during sleep: mdn/content#4713. Contributors to the standard previously discussed a version of this issue in Chrome and reached consensus that the clock should tick during sleep: #65.
I would like to suggest several related revisions to the High Resolution Time standard for the Web Performance Working Group's consideration.
First, the language that closed #65 (PR #69) does not expressly address what should happen during sleep.
Addressing the scenario would be valuable for implementers of the API, since operating systems typically offer separate monotonic clocks APIs that do and don't include sleep. Addressing the scenario would also be valuable for users of the API, who could better understand the expected behavior and document inconsistent behavior. Here's an example revision.
Second, I would suggest upgrading the informative note on this issue to a normative requirement. If the monotonic clock in a context depends on past sleep for that context, then the following use case cannot be reliably supported in real-world conditions.
If a High Resolution Time timestamp can vary by a context's sleep history, then timestamps are not comparable across contexts in real-world scenarios (where thread, process, and system sleep are frequent and unpredictable). Similarly, the example provided in Section 1.2 (Example 2) is not reliable in real-world scenarios. A stronger version of this normative requirement would be to migrate the per-context monotonic clocks entirely to the shared monotonic clock (i.e., the same clock ticking in all contexts, just with a per-context time origin). That might not have been realistic with OS capabilities ~6 years ago, but it might be realistic now. Some relevant context that I found helpful: #22 and #29.
Third, I would suggest adding semantics for
performance.timeOrigin + performance.now()
and how that compares toDate.now()
in the explanation of monotonic clocks (Section 6). There are normative requirements thatDOMHighResTimeStamp
count in milliseconds, that the reference point for the shared monotonic clock is ordinary ECMAScript time, and that a context's time origin be set with the shared monotonic clock. The only way I see to satisfy these normative requirements is ifperformance.timeOrigin + performance.now()
andDate.now()
both represent the current time, and should only differ because of either 1) user or automated adjustments to the system clock after the shared monotonic clock starts ticking, or 2) differences in underlying clock implementation (e.g., there might be different hardware clocks with slightly different frequencies). There are definitely use cases for thoseperformance.timeOrigin + performance.now()
semantics, where the goal is to timestamp events in a way that approximates real-world time, is monotonic, ideally is comparable across contexts (the prior item), and is not subject to user or operating system clock adjustments, assuming that the system clock was approximately correct when the shared monotonic timer started ticking. I recognize there have been prior discussions about how High Resolution Time relates toDate.now()
, with a resolution that the two APIs shouldn't have their values compared (e.g., #27). To be clear, I'm not suggesting a quantitative guarantee that the values provided by the two APIs will be similar, but rather, a semantic definition of how the two APIs relate and the specific conditions that can cause divergence over time.Fourth, I would suggest defining what the term "skew" means in the document, and perhaps using a different term instead. The notion, if I understand correctly from discussion in prior issues, is that NTP and similar automatic adjustments for clock errors should not change (skew) the monotonic clocks. Unfortunately, skew also typically means a difference between two clocks (which NTP tries to mitigate). So... depending on the meaning of "skew," the normative requirement that monotonic clocks not have "system clock skew" either means they must not change when the system clock changes, or they must change when the system clock changes. I would also suggest clarifying that monotonic adjustments to a monotonic clock are permissible (e.g., monotonic NTP corrections for oscillator frequency or
adjtime
corrections, seeCLOCK_MONOTONIC
vs.CLOCK_MONOTONIC_RAW
inclock_gettime
); the current text could be interpreted to prohibit any adjustments.The text was updated successfully, but these errors were encountered: