LibWeb: Report performance based timestamps relative to ESO time origin

This commit is contained in:
Tim Ledbetter 2025-01-07 10:08:14 +00:00 committed by Alexander Kalenik
commit 7488136a51
Notes: github-actions[bot] 2025-01-27 13:54:36 +00:00
12 changed files with 248 additions and 28 deletions

View file

@ -11,11 +11,12 @@
return;
}
let timestamp = performance.now();
let monotonicTime = performance.now();
let date = Date.now();
let relativeDate = date - performance.timeOrigin;
let allowedDifference = 300;
if (timestamp <= date - allowedDifference || timestamp >= date + allowedDifference) {
if (Math.abs(monotonicTime - relativeDate) >= allowedDifference) {
println('performance.now() should be close to Date.now(), but was ' + (timestamp - date));
return;
}

View file

@ -0,0 +1,45 @@
<!doctype html>
<html>
<head>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
</head>
<body>
<script>
const windowOrigin = performance.timeOrigin;
test(() => {
// Use a 30ms cushion when comparing with Date() to account for inaccuracy.
const startTime = Date.now();
assert_greater_than_equal(startTime + 30, windowOrigin, 'Date.now() should be at least as large as the window timeOrigin.');
const startNow = performance.now();
assert_less_than_equal(startTime, windowOrigin + startNow + 30, 'Date.now() should be close to window timeOrigin.');
}, 'Window timeOrigin is close to Date.now() when there is no system clock adjustment.');
const workerScript = 'postMessage({timeOrigin: performance.timeOrigin})';
const blob = new Blob([workerScript]);
async_test(function(t) {
const beforeWorkerCreation = performance.now();
const worker = new Worker(URL.createObjectURL(blob));
worker.addEventListener('message', t.step_func_done(function(event) {
const workerOrigin = event.data.timeOrigin;
assert_greater_than_equal(workerOrigin, windowOrigin + beforeWorkerCreation, 'Worker timeOrigin should be greater than the window timeOrigin.');
const afterWorkerCreation = performance.now();
assert_less_than_equal(workerOrigin - windowOrigin, afterWorkerCreation, 'Window and worker timeOrigins should be close.');
}));
}, 'Window and worker timeOrigins are close when created one after another.');
async_test(function(t) {
this.step_timeout(function() {
const workerCreation = performance.now();
const worker = new Worker(URL.createObjectURL(blob));
worker.addEventListener('message', t.step_func_done(function(event) {
const workerOrigin = event.data.timeOrigin;
assert_greater_than_equal(workerOrigin - windowOrigin, 200, 'We waited 200ms to spawn the second worker, so its timeOrigin should be greater than that of the window.');
}));
}, 200);
}, 'Window and worker timeOrigins differ when worker is created after a delay.');
</script>
</body>
</html>

View file

@ -0,0 +1,15 @@
<!doctype html>
<meta charset=utf-8>
<script>
self.GLOBAL = {
isWindow: function() { return true; },
isWorker: function() { return false; },
isShadowRealm: function() { return false; },
};
</script>
<script src="../resources/testharness.js"></script>
<script src="../resources/testharnessreport.js"></script>
<div id=log></div>
<script src="../user-timing/mark.any.js"></script>

View file

@ -0,0 +1,118 @@
// test data
var testThreshold = 20;
var expectedTimes = new Array();
function match_entries(entries, index)
{
var entry = entries[index];
var match = self.performance.getEntriesByName("mark")[index];
assert_equals(entry.name, match.name, "entry.name");
assert_equals(entry.startTime, match.startTime, "entry.startTime");
assert_equals(entry.entryType, match.entryType, "entry.entryType");
assert_equals(entry.duration, match.duration, "entry.duration");
}
function filter_entries_by_type(entryList, entryType)
{
var testEntries = new Array();
// filter entryList
for (var i in entryList)
{
if (entryList[i].entryType == entryType)
{
testEntries.push(entryList[i]);
}
}
return testEntries;
}
test(function () {
// create first mark
self.performance.mark("mark");
expectedTimes[0] = self.performance.now();
const entries = self.performance.getEntriesByName("mark");
assert_equals(entries.length, 1);
}, "Entry 0 is properly created");
test(function () {
// create second, duplicate mark
self.performance.mark("mark");
expectedTimes[1] = self.performance.now();
const entries = self.performance.getEntriesByName("mark");
assert_equals(entries.length, 2);
}, "Entry 1 is properly created");
function test_mark(index) {
test(function () {
const entries = self.performance.getEntriesByName("mark");
assert_equals(entries[index].name, "mark", "Entry has the proper name");
}, "Entry " + index + " has the proper name");
test(function () {
const entries = self.performance.getEntriesByName("mark");
assert_approx_equals(entries[index].startTime, expectedTimes[index], testThreshold);
}, "Entry " + index + " startTime is approximately correct (up to " + testThreshold +
"ms difference allowed)");
test(function () {
const entries = self.performance.getEntriesByName("mark");
assert_equals(entries[index].entryType, "mark");
}, "Entry " + index + " has the proper entryType");
test(function () {
const entries = self.performance.getEntriesByName("mark");
assert_equals(entries[index].duration, 0);
}, "Entry " + index + " duration == 0");
test(function () {
const entries = self.performance.getEntriesByName("mark", "mark");
assert_equals(entries[index].name, "mark");
}, "getEntriesByName(\"mark\", \"mark\")[" + index + "] returns an " +
"object containing a \"mark\" mark");
test(function () {
const entries = self.performance.getEntriesByName("mark", "mark");
match_entries(entries, index);
}, "The mark returned by getEntriesByName(\"mark\", \"mark\")[" + index
+ "] matches the mark returned by " +
"getEntriesByName(\"mark\")[" + index + "]");
test(function () {
const entries = filter_entries_by_type(self.performance.getEntries(), "mark");
assert_equals(entries[index].name, "mark");
}, "getEntries()[" + index + "] returns an " +
"object containing a \"mark\" mark");
test(function () {
const entries = filter_entries_by_type(self.performance.getEntries(), "mark");
match_entries(entries, index);
}, "The mark returned by getEntries()[" + index
+ "] matches the mark returned by " +
"getEntriesByName(\"mark\")[" + index + "]");
test(function () {
const entries = self.performance.getEntriesByType("mark");
assert_equals(entries[index].name, "mark");
}, "getEntriesByType(\"mark\")[" + index + "] returns an " +
"object containing a \"mark\" mark");
test(function () {
const entries = self.performance.getEntriesByType("mark");
match_entries(entries, index);
}, "The mark returned by getEntriesByType(\"mark\")[" + index
+ "] matches the mark returned by " +
"getEntriesByName(\"mark\")[" + index + "]");
}
for (var i = 0; i < expectedTimes.length; i++) {
test_mark(i);
}