tests: Vendor blink perf tests (#38654)

Vendors the [blink perf
tests](https://chromium.googlesource.com/chromium/src/+/HEAD/third_party/blink/perf_tests/).
These perf tests are useful to evaluate the performance of servo. 
The license that governs the perf tests is included in the folder. 
Running benchmark cases automatically is left to future work.

The update.py script is taken from mozjs and slightly adapted, so we can
easily filter
(and patch if this should be necessary in the future.

Testing: This PR just adds the perf_tests, but does not use or modify
them in any way.

---------

Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
This commit is contained in:
Jonathan Schwender 2025-08-17 11:54:04 +02:00 committed by GitHub
parent 7621332824
commit ee781b71b4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
648 changed files with 359694 additions and 0 deletions

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
var div = document.createElement("div");
var childDiv = document.createElement("div");
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers 'appendChild' and 'removeChild' in Dromaeo/dom-modify.html.",
setup: function() {
div.innerHTML = "";
},
run: function() {
var localDiv = div;
var localChildDiv = childDiv;
for (var i = 0; i < 50000; i++)
localDiv.appendChild(localChildDiv);
}});
</script>
</body>
</html>

View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers 'createElement', 'createTextNode' and 'cloneNode' in Dromaeo/dom-modify.html, and other DOM methods that return a new Node object.",
run: function() {
for (var i = 0; i < 5000; i++)
document.createElement("div");
}});
</script>
</body>
</html>

View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark repeatedly accesses document.implementation.",
run: function() {
for (var i = 0; i < 100000; ++i)
document.implementation;
}});
</script>
</body>
</html>

View file

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
var elements = [];
elements.push(document.createElement("div"));
elements.push(document.createElement("a"));
elements.push(document.createElement("br"));
elements.push(document.createElement("form"));
elements.push(document.createElement("canvas"));
elements.push(document.createElement("img"));
elements.push(document.createElement("details"));
elements.push(document.createElement("font"));
elements.push(document.createElement("span"));
elements.push(document.createElement("table"));
elements.push(document.createElement("tbody"));
elements.push(document.createElement("th"));
elements.push(document.createElement("tr"));
elements.push(document.createElement("td"));
PerfTestRunner.measureRunsPerSecond({
description: "A benchmark to test performance when accessing a DOM attribute on a prototype chain of multipe types of elements. See https://crbug.com/43394 for more background.",
run: function() {
var localElements = elements;
for (var i = 0; i < 10000; i++) {
for (var j = 0; j < 14; j++) {
elements[j].baseURI;
}
}
}});
</script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
var div = document.createElement("div");
div.appendChild(document.createElement("div"));
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers 'firstChild', 'lastChild', 'nextSibling' and 'previousSibling' in Dromaeo/dom-traverse.html, and other DOM attributes that return a Node object.",
run: function() {
var localDiv = div;
for (var i = 0; i < 100000; i++)
localDiv.firstChild;
}});
</script>
</body>
</html>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script>
PerfTestRunner.measureTime({
description: "Measures performance of creating one million divs without retaining references, then running the garbage collector.",
run: function() {
(function() {
for (var i = 0; i < 1000000; i++)
document.createElement("div");
})();
PerfTestRunner.gc();
}
});
</script>
</body>

View file

@ -0,0 +1,16 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script>
PerfTestRunner.measureTime({
description: "Measures performance of creating a half million divs that contain spans without retaining references, then running the garbage collector.",
run: function() {
(function() {
for (var i = 0; i < 500000; i++)
document.createElement("div").appendChild(document.createElement("span"));
})();
PerfTestRunner.gc();
}
});
</script>
</body>

View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script>
PerfTestRunner.measureTime({
description: "Measures performance of creating one million divs inside a div, releasing references, then running the garbage collector.",
run: function() {
(function() {
var root = document.createElement("div");
for (var i = 0; i < 1000000; i++)
root.appendChild(document.createElement("div"));
})();
PerfTestRunner.gc();
}
});
</script>
</body>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<body>
<div id="foo" role="group"></div>
<script src="../resources/runner.js"></script>
<script>
var div = document.getElementById("foo");
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers 'getAttribute' in Dromaeo/dom-attr.html, and other DOM methods that return a String.",
run: function() {
var localDiv = div;
for (var i = 0; i < 100000; i++)
localDiv.getAttribute("role");
}});
</script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<body>
<div id="foo"></div>
<script src="../resources/runner.js"></script>
<script>
var div = document.getElementById("foo");
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers 'getAttribute' in Dromaeo/dom-attr.html, and other DOM methods that return a String.",
run: function() {
var localDiv = div;
for (var i = 0; i < 100000; i++)
localDiv.getAttribute("id");
}});
</script>
</body>
</html>

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<body>
<div id="foo"></div>
<script src="../resources/runner.js"></script>
<script>
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers 'getElementById' in Dromaeo/dom-query.html, and other DOM methods that return a Node object.",
run: function() {
for (var i = 0; i < 100000; i++)
document.getElementById("foo");
}});
</script>
</body>
</html>

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<body>
<div></div>
<script src="../resources/runner.js"></script>
<script>
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers 'getElementsByTagName (not in document)', 'getElementsByTagName', 'getElementsByName (not in document)' and 'getElementsByName' in Dromaeo/dom-query.html, and other DOM methods that return a NodeList.",
run: function() {
for (var i = 0; i < 50000; i++)
document.getElementsByTagName("div");
}});
</script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<body>
<div id="foo"></div>
<script src="../resources/runner.js"></script>
<script>
var div = document.getElementById("foo");
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers 'element.property' in Dromaeo/dom-attr.html, 'innerHTML' in Dromaeo/dom-modify.html, and other DOM attributes that return a String.",
run: function() {
var localDiv = div;
for (var i = 0; i < 100000; i++)
localDiv.id;
}});
</script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<body>
<div id="foo"></div>
<script src="../resources/runner.js"></script>
<script>
var div = document.getElementById("foo");
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers 'element.property = value' in Dromaeo/dom-attr.html, and other DOM attributes that sets a String.",
run: function() {
var localDiv = div;
for (var i = 0; i < 50000; i++)
localDiv.id = "foo";
}});
</script>
</body>
</html>

View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<body>
<div id="foo"></div>
<script src="../resources/runner.js"></script>
<script>
for (var i = 0; i < 1000; i++) {
document.body.appendChild(document.createElement("div"));
}
var divs = document.getElementsByTagName("div");
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark measures performance of indexed property getters.",
run: function() {
var localDivs = divs;
for (var i = 0; i < 1000; i++)
localDivs[i];
}});
</script>
</body>
</html>

View file

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
var div = document.createElement("div");
var childDiv = document.createElement("div");
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers 'insertBefore' in Dromaeo/dom-modify.html and replaceChild()",
setup: function() {
div.innerHTML = "";
div.appendChild(childDiv);
},
run: function() {
var localDiv = div;
var localFirstChildOfDiv = div.firstChild;
var localChildDiv = childDiv;
for (var i = 0; i < 50000; i++)
localDiv.insertBefore(localChildDiv, localFirstChildOfDiv);
}});
</script>
</body>
</html>

View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
var div = document.createElement("div");
for (var i = 0; i < 1000; i++) {
var key = "key_" + i;
var value = "value_" + i;
div.dataset[key] = value;
}
function assertEquals(a, b) {
if (a !== b) console.log("assertion failed: not equal", a, b);
}
var i = 0;
for (var key in div.dataset) {
var ref_key = "key_" + i;
var ref_value = "value_" + i;
assertEquals(key, ref_key);
assertEquals(div.dataset[key], ref_value);
i++;
}
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers enumerator of named properties",
run: function() {
for (var key in div.dataset);
}});
</script>
</body>
</html>

View file

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
var div = document.createElement("div");
for (var i = 0; i < 100000; i++)
div.appendChild(document.createElement("div"));
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers 'childNodes' in Dromaeo/dom-traverse.html, and other DOM attributes that access NodeList.",
run: function() {
var childNodes = div.childNodes;
var length = div.childNodes.length;
for (var i = 0; i < length; i++)
childNodes[i];
}});
</script>
</body>
</html>

View file

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers DOM attributes that return integers.",
run: function() {
var localBody = document.body;
for (var i = 0; i < 100000; i++)
localBody.nodeType;
}});
</script>
</body>
</html>

View file

@ -0,0 +1,39 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script>
var isDone = false;
function runTest() {
var numRound = 1000;
var worker = new Worker('resources/worker.js');
var startTime = PerfTestRunner.now();
worker.onmessage = function(event) {
numRound--;
if (numRound > 0) {
worker.postMessage('next');
} else {
PerfTestRunner.measureValueAsync(PerfTestRunner.now() - startTime);
if (!isDone)
runTest();
}
};
worker.postMessage('start');
}
function testDone() {
isDone = true;
}
window.onload = function () {
PerfTestRunner.startMeasureValuesAsync({
description: "Measures time to run 1000 postMessage round trips in serial.",
unit: 'ms',
run: runTest,
done: testDone,
});
};
</script>
<div id="log"></div>
</body>

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1 @@
{"type":3,"mutations":[{"target":{"_index_":18,"transferred":1},"addedNodes":null,"removedNodes":null,"previousSibling":null,"nextSibling":null,"attributeName":"class","attributeNamespace":null,"oldValue":"candidateTable_victor","type":0,"propertyName":null,"value":"candidateTable_victor candidateTable_displayVictor","addedEvents":null,"removedEvents":null,"measure":null},{"target":{"_index_":35,"transferred":1},"addedNodes":null,"removedNodes":null,"previousSibling":null,"nextSibling":null,"attributeName":"class","attributeNamespace":null,"oldValue":"candidateTable_victor candidateTable_displayVictor","type":0,"propertyName":null,"value":"candidateTable_victor","addedEvents":null,"removedEvents":null,"measure":null},{"target":{"_index_":74,"transferred":1},"addedNodes":null,"removedNodes":null,"previousSibling":null,"nextSibling":null,"attributeName":"fill","attributeNamespace":null,"oldValue":"black","type":0,"propertyName":null,"value":"red","addedEvents":null,"removedEvents":null,"measure":null},{"target":{"_index_":76,"transferred":1},"addedNodes":null,"removedNodes":null,"previousSibling":null,"nextSibling":null,"attributeName":null,"attributeNamespace":null,"oldValue":"Region winner Steven Armstrong","type":1,"propertyName":null,"value":"Region winner ","addedEvents":null,"removedEvents":null,"measure":null},{"target":{"_index_":75,"transferred":1},"addedNodes":null,"removedNodes":null,"previousSibling":null,"nextSibling":null,"attributeName":"class","attributeNamespace":null,"oldValue":"candidateMap_tooltip candidateMap_showTooltip","type":0,"propertyName":null,"value":"candidateMap_tooltip","addedEvents":null,"removedEvents":null,"measure":null}]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,47 @@
const StructuredClonePerfTestRunner = (function() {
function pingPong(data) {
return new Promise((resolve, reject) => {
let beginSerialize, endSerialize, beginDeserialize, endDeserialize;
window.addEventListener('message', function listener(e) {
try {
e.data; // Force deserialization.
endDeserialize = PerfTestRunner.now();
window.removeEventListener('message', listener);
resolve([endSerialize - beginSerialize, endDeserialize - beginDeserialize]);
} catch (err) { reject(err); }
});
beginSerialize = PerfTestRunner.now();
window.postMessage(data, '*');
beginDeserialize = endSerialize = PerfTestRunner.now();
// While Chrome does the deserialize lazily when e.data is read, this
// isn't portable, so it's more fair to measure from when the message is
// posted.
});
}
return {
measureTimeAsync(test) {
let isDone = false;
PerfTestRunner.startMeasureValuesAsync({
description: test.description,
unit: 'ms',
warmUpCount: test.warmUpCount || 10,
iterationCount: test.iterationCount || 250,
done() { isDone = true; },
run: pingPongUntilDone,
});
function pingPongUntilDone() {
pingPong(test.data).then(([serializeTime, deserializeTime]) => {
console.log([serializeTime, deserializeTime]);
if (test.measure === 'serialize')
PerfTestRunner.measureValueAsync(serializeTime);
else if (test.measure === 'deserialize')
PerfTestRunner.measureValueAsync(deserializeTime);
if (!isDone) pingPongUntilDone();
});
}
},
};
})();

View file

@ -0,0 +1,45 @@
(module
(type $0 (func (param externref i32)))
(import "../clearCalls.js" "clearThruJS" (func $assembly/index/clearThruJS (param externref i32)))
(import "../clearCalls.js" "clearNoJS" (func $assembly/index/clearNoJS (param externref i32)))
(memory $0 0)
(export "clearManyTimesThruJS" (func $assembly/index/clearManyTimesThruJS))
(export "clearManyTimesNoJS" (func $assembly/index/clearManyTimesNoJS))
(export "memory" (memory $0))
(func $assembly/index/clearManyTimesThruJS (param $0 externref) (param $1 i32)
(local $2 i32)
loop $for-loop|0
local.get $1
local.get $2
i32.gt_s
if
local.get $0
i32.const 16384
call $assembly/index/clearThruJS
local.get $2
i32.const 1
i32.add
local.set $2
br $for-loop|0
end
end
)
(func $assembly/index/clearManyTimesNoJS (param $0 externref) (param $1 i32)
(local $2 i32)
loop $for-loop|0
local.get $1
local.get $2
i32.gt_s
if
local.get $0
i32.const 16384
call $assembly/index/clearNoJS
local.get $2
i32.const 1
i32.add
local.set $2
br $for-loop|0
end
end
)
)

View file

@ -0,0 +1,50 @@
const WorkerStructuredCloneDifferentPayloadsPerfTestRunner = (function() {
function pingPong(data) {
return new Promise((resolve, reject) => {
let mainThreadBeginSerialize, mainThreadEndDeserialize, iteration, numMessages;
iteration = 0;
numMessages = data['toWorker'].length;
worker.addEventListener('message', function listener(e) {
try {
e.data.sendData; // Force deserialization.
// keep sending messages to worker until worker runs out of responses.
if (!e.data.done && iteration < numMessages) {
iteration++;
worker.postMessage({'data' : data['toWorker'][iteration], 'iteration' : iteration});
} else {
mainThreadEndDeserialize = performance.now();
worker.removeEventListener('message', listener);
totalTime = mainThreadEndDeserialize - mainThreadBeginSerialize;
resolve([totalTime]);
}
} catch (err) { reject(err); }
});
mainThreadBeginSerialize = performance.now();
worker.postMessage({'data' : data['toWorker'][iteration], 'iteration' : iteration});
});
}
return {
measureTimeAsync(test) {
let isDone = false;
worker = new Worker('resources/worker-structured-clone-different-payloads.js');
PerfTestRunner.startMeasureValuesAsync({
description: test.description,
unit: 'ms',
warmUpCount: test.warmUpCount || 5,
iterationCount: test.iterationCount || 15,
done() { isDone = true; },
run: pingPongUntilDone,
});
function pingPongUntilDone() {
pingPong(test.data).then(([totalTime]) => {
console.log([totalTime]);
if (test.measure == 'roundtrip')
PerfTestRunner.measureValueAsync(totalTime);
if (!isDone) pingPongUntilDone();
});
}
},
};
})();

View file

@ -0,0 +1,15 @@
var xhr = new XMLHttpRequest();
xhr.open("GET", "data/preact-from-worker.json", false);
xhr.send(null);
var sendData = JSON.parse(xhr.responseText)
var length = sendData['fromWorker'].length;
self.onmessage = function(e) {
var data = e.data; // Force deserialization.
var iteration = e.data.iteration;
var done = false;
if (iteration == length - 1){
done = true;
}
self.postMessage({'sendData' : sendData['fromWorker'][iteration], 'done': done});
};

View file

@ -0,0 +1,51 @@
const WorkerStructuredClonePerfTestRunner = (function() {
function pingPong(data) {
return new Promise((resolve, reject) => {
let mainThreadBeginSerialize, mainThreadEndDeserialize, toWorkerTime, fromWorkerTime, totalTime;
worker.addEventListener('message', function listener(e) {
try {
e.data; // Force deserialization.
mainThreadEndDeserialize = performance.now();
worker.removeEventListener('message', listener);
// toWorkerTime: Time from main thread beginning serialize to end of worker deserialize
toWorkerTime = (e.data.workerDeserialize + (e.data.workerTimeOrigin - performance.timeOrigin)) - mainThreadBeginSerialize;
// fromWorkerTime: Time from worker beginning serialize to end of main thread deserialize
fromWorkerTime = mainThreadEndDeserialize - (e.data.workerDeserialize + (e.data.workerTimeOrigin - performance.timeOrigin));
// totalTime: Time from main thread beginning serialzie to end of main thread deserialize
totalTime = mainThreadEndDeserialize - mainThreadBeginSerialize
resolve([toWorkerTime, fromWorkerTime, totalTime]);
} catch (err) { reject(err); }
});
mainThreadBeginSerialize = performance.now();
worker.postMessage(data);
});
}
return {
measureTimeAsync(test) {
let isDone = false;
worker = new Worker('resources/worker-structured-clone.js');
PerfTestRunner.startMeasureValuesAsync({
description: test.description,
unit: 'ms',
warmUpCount: test.warmUpCount || 10,
iterationCount: test.iterationCount || 250,
done() { isDone = true; },
run: pingPongUntilDone,
});
function pingPongUntilDone() {
pingPong(test.data).then(([toWorkerTime, fromWorkerTime, totalTime]) => {
console.log([toWorkerTime, fromWorkerTime, totalTime]);
if (test.measure == 'toWorker')
PerfTestRunner.measureValueAsync(toWorkerTime);
else if (test.measure === 'fromWorker')
PerfTestRunner.measureValueAsync(fromWorkerTime);
else if (test.measure == 'roundtrip')
PerfTestRunner.measureValueAsync(totalTime);
if (!isDone) pingPongUntilDone();
});
}
},
};
})();

View file

@ -0,0 +1,7 @@
self.onmessage = function(e) {
var data = e.data; // Force deserialization
var workerDeserialize = performance.now();
self.postMessage({'recieveddData' : data,
'workerTimeOrigin' : performance.timeOrigin,
'workerDeserialize' : workerDeserialize});
};

View file

@ -0,0 +1,54 @@
const WorkerTextEncodedTransferablePerfTestRunner = (function() {
function pingPong(data) {
return new Promise((resolve, reject) => {
let sendData, textEncoder, textDecoder, mainThreadBeginEncode, mainThreadEndDecode, toWorkerTime, fromWorkerTime, totalTime;
textEncoder = new TextEncoder('utf-8');
textDecoder = new TextDecoder('utf-8');
worker.addEventListener('message', function listener(e) {
try {
textDecoder.decode(e.data.data);
mainThreadEndDecode = performance.now();
worker.removeEventListener('message', listener);
// toWorkerTime: time to encode the data, send it to the worker, and decode it on the worker
toWorkerTime = (e.data.workerDecode + (e.data.workerTimeOrigin - performance.timeOrigin)) - mainThreadBeginEncode;
// fromWorkerTime: time to encode the data on the worker, send it back to the main thread, and deocde it
fromWorkerTime = mainThreadEndDecode - (e.data.workerDecode + (e.data.workerTimeOrigin - performance.timeOrigin));
// totalTime: time to do the whole roundtrip
totalTime = mainThreadEndDecode - mainThreadBeginEncode
resolve([toWorkerTime, fromWorkerTime, totalTime]);
} catch (err) { reject(err); }
});
mainThreadBeginEncode = performance.now();
sendData = textEncoder.encode(data).buffer;
worker.postMessage({"data" : sendData}, [sendData]);
});
}
return {
measureTimeAsync(test) {
let isDone = false;
worker = new Worker('resources/worker-text-encoded-transferable.js');
PerfTestRunner.startMeasureValuesAsync({
description: test.description,
unit: 'ms',
warmUpCount: test.warmUpCount || 10,
iterationCount: test.iterationCount || 250,
done() { isDone = true; },
run: pingPongUntilDone,
});
function pingPongUntilDone() {
pingPong(test.data).then(([toWorkerTime, fromWorkerTime, totalTime]) => {
console.log([toWorkerTime, fromWorkerTime, totalTime]);
if (test.measure == 'toWorker')
PerfTestRunner.measureValueAsync(toWorkerTime);
else if (test.measure === 'fromWorker')
PerfTestRunner.measureValueAsync(fromWorkerTime);
else if (test.measure == 'roundtrip')
PerfTestRunner.measureValueAsync(totalTime);
if (!isDone) pingPongUntilDone();
});
}
},
};
})();

View file

@ -0,0 +1,11 @@
var textDecoder = new TextDecoder('utf-8');
var textEncoder = new TextEncoder('utf-8');
self.onmessage = function(e) {
var data = textDecoder.decode(e.data.data);
var workerDecode = performance.now();
var sendData = textEncoder.encode(data).buffer;
self.postMessage({'data' : sendData,
'workerTimeOrigin' : performance.timeOrigin,
'workerDecode' : workerDecode},
[sendData]);
};

View file

@ -0,0 +1,52 @@
const WorkerTransferablePerfTestRunner = (function() {
function pingPong(data) {
return new Promise((resolve, reject) => {
let sendData, mainThreadBeginTransfer, workerEndTransfer, toWorkerTime, fromWorkerTime, totalTime;
worker.addEventListener('message', function listener(e) {
try {
e.data.data;
workerEndTransfer = performance.now();
worker.removeEventListener('message', listener);
// toWorkerTime: Time for the main thread to transfer data to the worker
toWorkerTime = (e.data.mainThreadEndTransfer + (e.data.workerTimeOrigin - performance.timeOrigin)) - mainThreadBeginTransfer;
// fromWorkerTime: Time for the worker to transfer data back to the main thread
fromWorkerTime = workerEndTransfer - (e.data.mainThreadEndTransfer + (e.data.workerTimeOrigin - performance.timeOrigin));
// totalTime: Time from main thread beginning transfer to the end of the worker transfer
totalTime = workerEndTransfer - mainThreadBeginTransfer
resolve([toWorkerTime, fromWorkerTime, totalTime]);
} catch (err) { reject(err); }
});
sendData = data.slice(0); // Copy the data for every new transfer
mainThreadBeginTransfer = performance.now();
worker.postMessage({"data" : sendData}, [sendData]);
});
}
return {
measureTimeAsync(test) {
let isDone = false;
worker = new Worker('resources/worker-transferable.js');
PerfTestRunner.startMeasureValuesAsync({
description: test.description,
unit: 'ms',
warmUpCount: test.warmUpCount || 10,
iterationCount: test.iterationCount || 250,
done() { isDone = true;},
run: pingPongUntilDone,
});
function pingPongUntilDone() {
pingPong(test.data).then(([toWorkerTime, fromWorkerTime, totalTime]) => {
console.log([toWorkerTime, fromWorkerTime, totalTime]);
if (test.measure == 'toWorker')
PerfTestRunner.measureValueAsync(toWorkerTime);
else if (test.measure === 'fromWorker')
PerfTestRunner.measureValueAsync(fromWorkerTime);
else if (test.measure == 'roundtrip')
PerfTestRunner.measureValueAsync(totalTime);
if (!isDone) pingPongUntilDone();
});
}
},
};
})();

View file

@ -0,0 +1,8 @@
self.onmessage = function(e) {
var data = e.data.data;
var mainThreadEndTransfer = performance.now();
self.postMessage({'data' : data,
'workerTimeOrigin' : performance.timeOrigin,
'mainThreadEndTransfer' : mainThreadEndTransfer},
[data]);
};

View file

@ -0,0 +1,3 @@
self.onmessage = function(m) {
self.postMessage('received');
};

View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
let dataArray = [];
for (let i = 0; i < 100000; i++) {
// We are interested in the conversion of JS arrays to C++ sequences, not in
// the JS string to C++ string conversion, so just push empty strings into
// the array.
dataArray.push('');
}
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark measures the overhead of converting JavaScript objects into WebIDL sequences (fast path for arrays)",
run: function() {
new Blob(dataArray);
}});
</script>
</body>
</html>

View file

@ -0,0 +1,30 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
let dataArray = [];
for (let i = 0; i < 100000; i++)
dataArray.push('');
let iterableData = {
[Symbol.iterator]() {
var count = 0;
return {
next() {
if (count >= dataArray.length)
return {done: true};
return {done: false, value: dataArray[count++]};
}
}
}
};
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark measures the overhead of converting JavaScript objects into WebIDL sequences (slow path using the @@iteratorprotocol)",
run: function() {
new Blob(iterableData);
}});
</script>
</body>
</html>

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script>
var length = 1000000;
var obj = [];
for (var i = 0; i < length; i++)
obj.push(undefined);
var worker = new Worker('resources/worker.js');
worker.onmessage = function(event) {
console.log("received");
};
PerfTestRunner.measureTime({
description: "Measures performance of serializing a long array containing 'undefined's.",
run: function() {
worker.postMessage(obj);
}
});
</script>
</body>

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script>
var log2Length = 23;
var str = "a";
for (var i = 0; i < log2Length; i++)
str = str + str;
var worker = new Worker('resources/worker.js');
worker.onmessage = function(event) {
console.log("received");
};
PerfTestRunner.measureTime({
description: "Measures performance of serializing a long string.",
run: function() {
worker.postMessage(str);
}
});
</script>
</body>

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script>
var length = 200000;
var obj = {}; // obj does not have a 'length' property.
for (var i = 0; i < length; i++)
obj['key' + i] = i;
var worker = new Worker('resources/worker.js');
worker.onmessage = function(event) {
console.log("received");
};
PerfTestRunner.measureTime({
description: "Measures performance of serializing a large map object.",
run: function() {
worker.postMessage(obj);
}
});
</script>
</body>

View file

@ -0,0 +1,22 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script>
var length = 1000;
var obj = [];
for (var i = 0; i < length; i++)
obj = [obj];
var worker = new Worker('resources/worker.js');
worker.onmessage = function(event) {
console.log("received");
};
PerfTestRunner.measureTime({
description: "Measures performance of serializing a long chaining nested array.",
run: function() {
worker.postMessage(obj);
}
});
</script>
</body>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<body>
<div id="foo" role="group"></div>
<script src="../resources/runner.js"></script>
<script>
var div = document.getElementById("foo");
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers 'setAttribute' in Dromaeo/dom-attr.html and other DOM methods that return an undefined.",
run: function() {
var localDiv = div;
for (var i = 0; i < 10000; i++)
localDiv.setAttribute("role", "group");
}});
</script>
</body>
</html>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html>
<body>
<div id="foo"></div>
<script src="../resources/runner.js"></script>
<script>
var div = document.getElementById("foo");
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers 'setAttribute' in Dromaeo/dom-attr.html and other DOM methods that return an undefined.",
run: function() {
var localDiv = div;
for (var i = 0; i < 10000; i++)
localDiv.setAttribute("id", "foo");
}});
</script>
</body>
</html>

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/structured-clone-perf-test.js"></script>
<script>
StructuredClonePerfTestRunner.measureTimeAsync({
description: "Measures performance of deserializing JSON-like data.",
data: JSON.parse(PerfTestRunner.loadFile("resources/data/blink-dev.json")),
measure: "deserialize",
});
</script>
</body>

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/structured-clone-perf-test.js"></script>
<script>
StructuredClonePerfTestRunner.measureTimeAsync({
description: "Measures performance of serializing JSON-like data.",
data: JSON.parse(PerfTestRunner.loadFile("resources/data/blink-dev.json")),
measure: "serialize",
});
</script>
</body>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/structured-clone-perf-test.js"></script>
<script>
// This simulates a long string being sent, such as JSON data as text, or a
// large data URI.
const log2Length = 23;
let str = 'a';
for (let i = 0; i < log2Length; i++) str += str;
StructuredClonePerfTestRunner.measureTimeAsync({
description: "Measures performance of deserializing a long string.",
data: str,
measure: "deserialize",
});
</script>
</body>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/structured-clone-perf-test.js"></script>
<script>
// This simulates a long string being sent, such as JSON data as text, or a
// large data URI.
const log2Length = 23;
let str = 'a';
for (let i = 0; i < log2Length; i++) str += str;
StructuredClonePerfTestRunner.measureTimeAsync({
description: "Measures performance of serializing a long string.",
data: str,
measure: "serialize",
});
</script>
</body>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script>
var length = 1000000;
var source = new Array(length);
for (var i = 0; i < length; i++)
source[i] = i;
PerfTestRunner.measureRunsPerSecond({
description: "Measures performance of creating a Uint8Array from an existing one million element Array which contains integers beyond the range of an unsigned 8-bit integer.",
run: function() {
var target = new Uint8Array(source);
}
});
</script>
</body>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script>
var length = 1000000;
var source = new Uint8Array(length);
for (var i = 0; i < length; i++)
source[i] = i;
PerfTestRunner.measureRunsPerSecond({
description: "Measures performance of creating a Uint8Array from an existing Uint8Array.",
run: function() {
var target = new Uint8Array(source);
}
});
</script>
</body>

View file

@ -0,0 +1,18 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script>
var length = 1000000;
var source = new Uint8Array(length);
for (var i = 0; i < length; i++)
source[i] = i;
PerfTestRunner.measureRunsPerSecond({
description: "Measures performance of creating a Float64Array from an existing one million element Uint8Array.",
run: function() {
var target = new Float64Array(source);
}
});
</script>
</body>

View file

@ -0,0 +1,19 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script>
var length = 1000000;
var source = new Uint8Array(length);
for (var i = 0; i < length; i++)
source[i] = i;
var target = new Float64Array(length);
PerfTestRunner.measureRunsPerSecond({
description: "Measures performance of setting a Float64Array to a Uint8Array using Float64Array.prototype.set.",
run: function() {
target.set(source);
}
});
</script>
</body>

View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
var div = document.createElement("div");
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers undefined DOM attributes that return a null.",
run: function() {
var localDiv = div;
for (var i = 0; i < 100000; i++)
localDiv.firstChild;
}});
</script>
</body>
</html>

View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers 'getElementById (not in document)' in Dromaeo/dom-query.html, and other Node-query methods that return a null.",
run: function() {
for (var i = 0; i < 100000; i++)
document.getElementById("foo");
}});
</script>
</body>
</html>

View file

@ -0,0 +1,17 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
var div = document.createElement("div");
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers undefined DOM attributes that return an empty String.",
run: function() {
var localDiv = div;
for (var i = 0; i < 100000; i++)
localDiv.id;
}});
</script>
</body>
</html>

View file

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<body>
<canvas id="cvs" style="border: 1px solid black"></canvas>
<script src="../resources/runner.js"></script>
<script>
function clearThruJS(context, mask) {
context.clear(mask);
}
const clearNoJS =
Function.prototype.call.bind(WebGLRenderingContext.prototype.clear);
const imports = {
'../clearCalls.js': {
'clearThruJS': clearThruJS,
'clearNoJS': clearNoJS
}
};
fetch("resources/wasm_webgpu.wasm").then(
response => response.arrayBuffer()).then(
buffer => {console.log(buffer); return WebAssembly.compile(buffer)}).then(
wasmModule => WebAssembly.instantiate(wasmModule, imports)).then(
instance => {
const testFuncNoJS = instance.exports.clearManyTimesNoJS;
const gl = cvs.getContext("webgl");
const kClearsPerIteration = 1_000_000;
PerfTestRunner.measureTime({
description: 'Test direct calls from WebAssembly to ' +
'WebGLRenderingContext.prototype.clear, enabled by ' +
'Function.prototype.call.bind',
setup: function() {},
run: function() {
testFuncNoJS(gl, kClearsPerIteration);
},
iterationCount: 5
});
});
</script>
</body>
</html>

View file

@ -0,0 +1,41 @@
<!DOCTYPE html>
<html>
<body>
<canvas id="cvs" style="border: 1px solid black"></canvas>
<script src="../resources/runner.js"></script>
<script>
function clearThruJS(context, mask) {
context.clear(mask);
}
const clearNoJS =
Function.prototype.call.bind(WebGLRenderingContext.prototype.clear);
const imports = {
'../clearCalls.js': {
'clearThruJS': clearThruJS,
'clearNoJS': clearNoJS
}
};
fetch("resources/wasm_webgpu.wasm").then(
response => response.arrayBuffer()).then(
buffer => {console.log(buffer); return WebAssembly.compile(buffer)}).then(
wasmModule => WebAssembly.instantiate(wasmModule, imports)).then(
instance => {
const testFuncThruJS = instance.exports.clearManyTimesThruJS;
const gl = cvs.getContext("webgl");
const kClearsPerIteration = 1_000_000;
PerfTestRunner.measureTime({
description: 'Test calls from WebAssembly to ' +
'WebGLRenderingContext.prototype.clear through ' +
'JavaScript',
setup: function() {},
run: function() {
testFuncThruJS(gl, kClearsPerIteration);
},
iterationCount: 5
});
});
</script>
</body>
</html>

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/worker-structured-clone-different-payloads-perf-test.js"></script>
<script>
WorkerStructuredCloneDifferentPayloadsPerfTestRunner.measureTimeAsync({
description: "Measures performance of worker round-trip with structured clone, for JSON-like data where different payloads are sent back and forth.",
data: JSON.parse(PerfTestRunner.loadFile("resources/data/preact-to-worker.json")),
measure: "roundtrip",
});
</script>
</body>

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/worker-structured-clone-perf-test.js"></script>
<script>
WorkerStructuredClonePerfTestRunner.measureTimeAsync({
description: "Measures performance of sending JSON-like data from a worker back to the main thread using deserialization.",
data: JSON.parse(PerfTestRunner.loadFile("resources/data/blink-dev.json")),
measure: "fromWorker",
});
</script>
</body>

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/worker-structured-clone-perf-test.js"></script>
<script>
WorkerStructuredClonePerfTestRunner.measureTimeAsync({
description: "Measures performance of worker round-trip with structured clone, for JSON-like data.",
data: JSON.parse(PerfTestRunner.loadFile("resources/data/blink-dev.json")),
measure: "roundtrip",
});
</script>
</body>

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/worker-structured-clone-perf-test.js"></script>
<script>
WorkerStructuredClonePerfTestRunner.measureTimeAsync({
description: "Measures performance of sending JSON-like data to a worker with deserialization.",
data: JSON.parse(PerfTestRunner.loadFile("resources/data/blink-dev.json")),
measure: "toWorker",
});
</script>
</body>

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/worker-structured-clone-perf-test.js"></script>
<script>
WorkerStructuredClonePerfTestRunner.measureTimeAsync({
description: "Measures performance of sending JSON data representing a Worker DOM DBMon from a worker back to the main thread using deserialization.",
data: JSON.parse(PerfTestRunner.loadFile("resources/data/WorkerDOM-DBMon.json")),
measure: "fromWorker",
});
</script>
</body>

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/worker-structured-clone-perf-test.js"></script>
<script>
WorkerStructuredClonePerfTestRunner.measureTimeAsync({
description: "Measures performance of sending JSON data representing a Worker DOM Map from a worker back to the main thread using deserialization.",
data: JSON.parse(PerfTestRunner.loadFile("resources/data/WorkerDOM-Map.json")),
measure: "fromWorker",
});
</script>
</body>

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/worker-text-encoded-transferable-perf-test.js"></script>
<script>
WorkerTextEncodedTransferablePerfTestRunner.measureTimeAsync({
description: "Measures performance of sending text encoded JSON data back to the main thread from a worker",
data: PerfTestRunner.loadFile("resources/data/blink-dev.json"),
measure: "fromWorker",
});
</script>
</body>

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/worker-text-encoded-transferable-perf-test.js"></script>
<script>
WorkerTextEncodedTransferablePerfTestRunner.measureTimeAsync({
description: "Measures performance of worker round-trip with text-encoded data sent as a transferable.",
data: PerfTestRunner.loadFile("resources/data/blink-dev.json"),
measure: "roundtrip",
});
</script>
</body>

View file

@ -0,0 +1,12 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/worker-text-encoded-transferable-perf-test.js"></script>
<script>
WorkerTextEncodedTransferablePerfTestRunner.measureTimeAsync({
description: "Measures performance of encoding JSON data to send to worker thread as a transferable",
data: PerfTestRunner.loadFile("resources/data/blink-dev.json"),
measure: "toWorker",
});
</script>
</body>

View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/worker-transferable-perf-test.js"></script>
<script>
var data = new Uint32Array(10485760);
for (var i = 0; i < data.length; i++) { data[i] = i; }
WorkerTransferablePerfTestRunner.measureTimeAsync({
description: "Measures performance of sending an array buffer as a transferable to the main thread from a worker.",
data: data.buffer,
measure: "fromWorker",
});
</script>
</body>

View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/worker-transferable-perf-test.js"></script>
<script>
var data = new Uint32Array(10485760);
for (var i = 0; i < data.length; i++) { data[i] = i; }
WorkerTransferablePerfTestRunner.measureTimeAsync({
description: "Measures performance of worker round-trip using transferable to send an array buffer.",
data: data.buffer,
measure: "roundtrip",
});
</script>
</body>

View file

@ -0,0 +1,14 @@
<!DOCTYPE html>
<body>
<script src="../resources/runner.js"></script>
<script src="resources/worker-transferable-perf-test.js"></script>
<script>
var data = new Uint32Array(10485760);
for (var i = 0; i < data.length; i++) { data[i] = i; }
WorkerTransferablePerfTestRunner.measureTimeAsync({
description: "Measures performance of sending an array buffer as a transferable to a worker.",
data: data.buffer,
measure: "toWorker",
});
</script>
</body>