javascriptnode.jsperformance.now

toFixed() behavior on performance.now()


When using toFixed on performance.now, it reveals some digits which I assume normally rounded. But it seems, the range changes based on platform.

On chrome(v87.0.4280.66), it can get up to 35 digits

window.performance.now().toFixed(35); // "241989.00499999945168383419513702392578125"

On node.js(v15.2.1), it's only up to 28.

performance.now().toFixed(28) // "1092.9840000011026859283447265625"

Same behavior exist on performance.timeOrigin too. I assume that it is possible to make much more accurate measurements with performance.now() but that accuracy depends on hardware and software factors so they just keep that accuracy on minimum standart.

  1. Does using toFixed(100) on performance.now() makes it more accurate?
  2. What factors affect range of performance.now()?
  3. Can we safely say that (performance.timeOrigin + performance.now()).toFixed(12) let's us measure the time accurate up to almost femtoseconds(10⁻¹⁵) or at least much much more accurate than the Date.now()?

Solution

  • Node's performance.now is literally:

    function now() {
      const hr = process.hrtime();
      return hr[0] * 1000 + hr[1] / 1e6;
    }
    

    Its accuracy is nanoseconds. (So not 26 digits after the point that's meaningless in that API). This just calls uv_hrtime (see node_process_methods.cc) which does clock_gettime which is just a standard way to get nanosecond time.

    In browsers the situation is worse - because of timing attacks that do fingerprinting or cache value extraction performance.now is less accurate:

    To offer protection against timing attacks and fingerprinting, the precision of performance.now() might get rounded depending on browser settings.

    So you can really on rely on milliseconds value.

    What it returns is clamped in chrome. See time_clamper.cc for more info. Basically its percision is limited to:

    static constexpr double kResolutionSeconds = 5e-6;
    

    Intentionally.

    As the other answer points out .toFixed just formats a number as a string and is unrelated to any of this.


    Note: the fact an API is precise to X digits does not in any way indicate digits after the Xth are zero. It only means that you can only rely on accuracy up to that digit.