Source code
Revision control
Copy as Markdown
Other Tools
Test Info: Warnings
- This test gets skipped with pattern: os == 'android' OR tsan
- Manifest: dom/serviceworkers/test/performance/perftest.toml
<!DOCTYPE HTML>
<html>
<head>
<title>Service worker performance test: update</title>
</head>
<div id="content"></div>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="../utils.js"></script>
<script src="perfutils.js"></script>
<script>
"use strict";
const VACUOUS_UPDATE = "Vacuous update";
const SERVER_UPDATE = "Server update";
const MAIN_CALLBACK = "Main callback";
const SW_CALLBACK = "SW callback";
const UPDATE_INTERNALS = "Update internals";
var journal = {};
journal[VACUOUS_UPDATE] = [];
journal[SERVER_UPDATE] = [];
journal[MAIN_CALLBACK] = [];
journal[SW_CALLBACK] = [];
journal[UPDATE_INTERNALS] = [];
const ITERATIONS = 11;
var perfMetadata = {
owner: "DOM LWS",
name: "Service Worker Update",
description: "Test updating.",
options: {
default: {
perfherder: true,
perfherder_metrics: [
// Here, we can't use the constants defined above because perfherder
// grabs data from the parse tree.
{ name: "Vacuous update", unit: "ms", shouldAlert: true },
{ name: "Server update", unit: "ms", shouldAlert: true },
{ name: "Main callback", unit: "ms", shouldAlert: true },
{ name: "SW callback", unit: "ms", shouldAlert: true },
{ name: "Update internals", unit: "ms", shouldAlert: true },
],
verbose: true,
manifest: "perftest.toml",
manifest_flavor: "plain",
},
},
};
async function testVacuousUpdate() {
async function measure() {
let reg = await navigator.serviceWorker.register("sw_empty.js");
await waitForState(reg.installing, "activated");
let begin_ts = performance.now();
await reg.update();
let end_ts = performance.now();
await reg.unregister();
journal[VACUOUS_UPDATE].push(end_ts - begin_ts);
}
for (let i = 0; i < ITERATIONS; i++) {
await measure();
}
}
async function testServerUpdate() {
async function measure() {
await startProfiler();
let reg = await navigator.serviceWorker.register("sw_serverupdate.sjs");
let promiseSW = new Promise((resolve, reject) => {
window.onmessage = (e) => {
is(e.data, "updatefound");
resolve(performance.now());
};
});
let callbackCounter = 0;
let promiseMain = new Promise((resolve, reject) => {
reg.onupdatefound = (e) => {
callbackCounter++;
// The first "update" happens for the original script,
// and isn't what we're interested in measuring.
if (callbackCounter == 2) {
resolve(performance.now());
}
};
});
is(callbackCounter, 0);
await waitForState(reg.installing, "activated");
is(callbackCounter, 1);
let content = document.getElementById("content");
let iframe = document.createElement("iframe");
content.appendChild(iframe);
iframe.setAttribute("src", "./fwd_messages_upward.html");
let begin_ts = performance.now();
await reg.update();
let endUpdate_ts = performance.now();
let endMainCallback_ts = await promiseMain;
let endSWCallback_ts = await promiseSW;
let pdata = await stopProfiler();
let internals_ms = inspectProfile(pdata, [
"ServiceWorkerRegistration::Update",
"ServiceWorkerRegistration::Update (inner)",
"ServiceWorkerUpdateJob::AsyncExecute",
"ServiceWorkerUpdateJob::Update",
"ServiceWorkerUpdateJob::Install"
]);
await reg.unregister();
journal[SERVER_UPDATE].push(endUpdate_ts - begin_ts);
journal[MAIN_CALLBACK].push(endMainCallback_ts - begin_ts);
journal[SW_CALLBACK].push(endSWCallback_ts - begin_ts);
journal[UPDATE_INTERNALS].push(internals_ms);
}
for (let i = 0; i < ITERATIONS; i++) {
await measure();
}
}
add_task(async () => {
await SpecialPowers.pushPrefEnv({
set: [["dom.serviceWorkers.enabled", true],
["dom.serviceWorkers.testing.enabled", true],
["dom.serviceWorkers.update_delay", 0]]
});
add_task(() => SpecialPowers.popPrefEnv());
ok(true);
});
add_task(testVacuousUpdate);
add_task(testServerUpdate);
add_task(() => reportMetrics(journal));
</script>
<body>
<div id="content"></div>
</body>
</html>