function ok(a, msg) { postMessage({ type: "status", status: !!a, msg }); } function is(a, b, msg) { ok(a === b, msg); } function finish() { postMessage({ type: "finish" }); } let isRounded = (x, expectedPrecision) => { let rounded = Math.floor(x / expectedPrecision) * expectedPrecision; // First we do the perfectly normal check that should work just fine if (rounded === x || x === 0) { return true; } // When we're diving by non-whole numbers, we may not get perfect // multiplication/division because of floating points. // When dealing with ms since epoch, a double's precision is on the order // of 1/5 of a microsecond, so we use a value a little higher than that as // our epsilon. // To be clear, this error is introduced in our re-calculation of 'rounded' // above in JavaScript. if (Math.abs(rounded - x + expectedPrecision) < 0.0005) { return true; } else if (Math.abs(rounded - x) < 0.0005) { return true; } // Then we handle the case where you're sub-millisecond and the timer is not // We check that the timer is not sub-millisecond by assuming it is not if it // returns an even number of milliseconds if (expectedPrecision < 1 && Math.round(x) == x) { if (Math.round(rounded) == x) { return true; } } ok( false, "Looming Test Failure, Additional Debugging Info: Expected Precision: " + expectedPrecision + " Measured Value: " + x + " Rounded Vaue: " + rounded + " Fuzzy1: " + Math.abs(rounded - x + expectedPrecision) + " Fuzzy 2: " + Math.abs(rounded - x) ); return false; }; function runTimerTests(expectedPrecision) { ok( isRounded(performance.timeOrigin, expectedPrecision), `In a worker, for reduceTimerPrecision, performance.timeOrigin is not correctly rounded: ` + performance.timeOrigin ); // Try to add some entries. performance.mark("Test"); performance.mark("Test-End"); performance.measure("Test-Measure", "Test", "Test-End"); // Check the entries in performance.getEntries/getEntriesByType/getEntriesByName. is( performance.getEntries().length, 3, "In a worker, for reduceTimerPrecision: Incorrect number of entries for performance.getEntries() for workers: " + performance.getEntries().length ); for (var i = 0; i < 3; i++) { let startTime = performance.getEntries()[i].startTime; let duration = performance.getEntries()[i].duration; ok( isRounded(startTime, expectedPrecision), "In a worker, for reduceTimerPrecision(" + expectedPrecision + "), performance.getEntries(" + i.toString() + ").startTime is not rounded: " + startTime.toString() ); ok( isRounded(duration, expectedPrecision), "In a worker, for reduceTimerPrecision(" + expectedPrecision + "), performance.getEntries(" + i.toString() + ").duration is not rounded: " + duration.toString() ); } is( performance.getEntriesByType("mark").length, 2, "In a worker, for reduceTimerPrecision: Incorrect number of entries for performance.getEntriesByType() for workers: " + performance.getEntriesByType("resource").length ); is( performance.getEntriesByName("Test", "mark").length, 1, "In a worker, for reduceTimerPrecision: Incorrect number of entries for performance.getEntriesByName() for workers: " + performance.getEntriesByName("Test", "mark").length ); finish(); } self.onmessage = function (e) { if (e.data.type === "runTimerTests") { runTimerTests(e.data.precision); } else { ok(false, "Unknown message type"); } };