Skip to content

Issue with "performance.now()": Chrome, Firefox, and Safari are not spec compliant on certain platforms #4713

@jonathanmayer

Description

@jonathanmayer

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 to performance.timing.navigationStart from the Navigation Timing spec. In the Level 2 spec, performance.now() is relative to performance.timeOrigin, which is defined in the spec.

There are two key differences between these reference times.

  1. The triggering conditions for navigationStart and timeOrigin are a little different. navigationStart timestamps a document fetch or an unload prompt (if any), while timeOrigin 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).
  2. 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 that performance.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.

Chrome/Chromium (bug) Firefox (bug) Safari/WebKit (bug)
Windows N/A
macOS 🚫 🚫 🚫
Linux 🚫 🚫 🚫 (except maybe WebKitGTK?)
Android 🚫 🚫 N/A
iOS N/A (WebKit wrapper) N/A (WebKit wrapper) 🚫
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 the performance.timeOrigin and DOMHighResTimeStamp pages.

What did you expect to see?

  • The description is for High Resolution Time Level 2, but the example is for the original spec (referencing 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.
  • A description of the browser- and platform-specific inconsistencies in sleep behavior, and what that could mean for use cases.
  • A mention of the Chrome and Firefox performance.timeOrigin bugs, and what those could mean for use cases.
  • A mention of the High Resolution Time clock drift behavior on macOS, and what that could mean for use cases.
  • An explicit indication that, while Safari/WebKit does support performance.now(), it has implemented the original High Resolution Time semantics and not the High Resolution Time Level 2 semantics.
  • Further explanation of the High Resolution Time Level 2 shared monotonic clock and per-document monotonic clock concepts would be valuable.

Did you test this? If so, how?

I've confirmed the following behaviors with both testing and code review:

  • Ticking During Sleep
    • Chrome: Windows, macOS, Linux
    • Firefox: Windows, macOS, Linux
    • Safari: macOS
  • Time Origin Set with the System Clock
    • Chrome: macOS and Linux
    • Firefox: macOS and Linux
  • Clock Drift on macOS
    • Chrome: macOS
    • Firefox: macOS
    • Safari: macOS
MDN Content page report details

Metadata

Metadata

Assignees

No one assigned

    Labels

    Content:WebAPIWeb API docseffort: smallThis task is a small effort.help wantedIf you know something about this topic, we would love your help!

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions