Search code examples
javascriptv8

v8 Atomics.wait timeout why is the error so large?


v8 shell execute the code below:

var msleep = n => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, n);
var t = Date.now();msleep(1000);Date.now() - t;

output:

1005

Why are there errors of a few milliseconds?

Here is an example of rust with an error of only 0.1 milliseconds.


Solution

  • Maybe your machine was busy? That's the primary reason why anything can take longer than expected.

    Note that you're measuring not just the timeout, but also the function call, creation of objects (which can trigger a short burst of GC activity), message loop pumping, and calling into system libraries.

    The latter in particular could explain this: on some operating systems, the default timer resolution is coarser than 1ms, so when the requested timeout runs out, the kernel might wait until its next timer tick before it notifies the process.

    FWIW, I can't reproduce your observations. I'm seeing mostly 1000 and sometimes 1001, which is pretty much what I would expect:

    d8> var msleep = n => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, n);
    d8> function measure() { var t = Date.now(); msleep(1000); return (Date.now() - t); }
    d8> for (var i = 0; i < 30; i++) print(measure());
    1000
    1000
    1001
    1000
    1000
    1000
    1000
    1001
    1000
    1000
    1000
    1000
    1001
    1000
    1000
    1000
    1000
    1001
    1000
    1000
    1000
    1000
    1000
    1000
    1000
    1000
    1000
    1001
    1000
    1000
    

    It is generally not advisable to rely on the accuracy of timeouts. E.g. if you want to build a stopwatch that doesn't drift, then take a start time and compare to that, like so:

    var start_time;
    function start_stopwatch() {
      start_time = Date.now();
      window.setTimeout(update_display, 1000);
    }
    function update_display() {
      var current_time = Date.now();
      call_display_function(current_time - start_time);
      window.setTimeout(update_display, 1000);  // Could be 876 for all we care.
    }
    

    Instead of:

    var elapsed;
    function start_stopwatch_DONT_DO_THIS() {
      elapsed = 0;
      window.setTimeout(update_display_DONT_DO_THIS, 1000);
    }
    function update_display_DONT_DO_THIS() {
      elapsed += 1000;  // This is going to be inaccurate!
      call_display_function(elapsed);
      window.setTimeout(update_display_DONT_DO_THIS, 1000);
    }