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,4 @@
monorail {
component: "Speed>Benchmark"
}
team_email: "benchmarking-dev@chromium.org"

View file

@ -0,0 +1,3 @@
haraken@chromium.org
ikilpatrick@chromium.org
kojii@chromium.org

View file

@ -0,0 +1 @@
Please refer to [blink_perf guide](../../../docs/speed/benchmark/harnesses/blink_perf.md).

View file

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
var longStr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ";
for (var i = 0; i < 15; i++)
longStr = longStr + longStr;
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers `atob` where the input has whitespace.",
setup: function() {},
run: function() {
atob(longStr);
}
});
</script>
</body>
</html>

View file

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
var longStr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (var i = 0; i < 15; i++)
longStr = longStr + longStr;
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers `atob`.",
setup: function() {},
run: function() {
atob(longStr);
}
});
</script>
</body>
</html>

View file

@ -0,0 +1,21 @@
<!DOCTYPE html>
<html>
<body>
<script src="../resources/runner.js"></script>
<script>
var longStr = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (var i = 0; i < 15; i++)
longStr = longStr + longStr;
var binary = atob(longStr);
PerfTestRunner.measureRunsPerSecond({
description: "This benchmark covers `btoa`.",
setup: function() {},
run: function() {
btoa(binary);
}
});
</script>
</body>
</html>

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>

View file

@ -0,0 +1,40 @@
<!DOCTYPE html>
<script src="../resources/runner.js"></script>
<script src="./resources/utils.js"></script>
<style id=style></style>
<div id=root class=myscope></div>
<script>
const SELECTORS = 1000;
function makeStyle() {
let selectors = [...Array(SELECTORS).keys()].map(x => `.a${x}`);
// Creates a selector list which is expensive to evaluate:
// (.a1, .a2, .a3 ... .a<n-1>, .myscope)
return `
@scope (${selectors.join(',')}, .myscope) {
div {
margin: 1px;
}
}
`;
}
function setup() {
style.textContent = makeStyle();
createDOMTree(root, /* siblings */ 2, /* depth */ 11);
}
setup();
PerfTestRunner.measureTime({
description: '@scope with many ancestors',
run: () => {
root.offsetTop;
root.classList.toggle('myscope');
root.offsetTop;
root.classList.toggle('myscope');
}
});
</script>

View file

@ -0,0 +1,70 @@
<!DOCTYPE html>
<script src="../resources/runner.js"></script>
<script src="./resources/utils.js"></script>
<style id=style></style>
<div id=root></div>
<script>
const SELECTORS = 1000;
const DOM_WIDTH = 10;
const DOM_DEPTH = 1000;
function makeStyle() {
let selectors = [...Array(SELECTORS).keys()].map(x => `.a${x}`);
// Creates a selector list which is expensive to evaluate:
// (.a1, .a2, .a3 ... .a<n-1>, ...)
return `
@scope (:not(:is(${selectors.join(',')})).foo) {
div:empty:not(.bar) {
margin: 1px;
}
}
`;
}
function makeChain(n) {
if (n <= 0) {
return null;
}
let element = document.createElement('div');
let child = makeChain(n - 1);
if (child != null) {
element.appendChild(child);
}
return element;
}
let leaf_nodes = [];
function setup() {
style.textContent = makeStyle();
for (let i = 0; i < DOM_WIDTH; ++i) {
root.appendChild(makeChain(DOM_DEPTH));
}
leaf_nodes = document.querySelectorAll('div:empty');
}
setup();
PerfTestRunner.measureTime({
description: 'Non-matching ancestor via :scope',
run: () => {
root.offsetTop;
for (let e of leaf_nodes) {
e.classList.toggle('bar');
}
root.offsetTop;
for (let e of leaf_nodes) {
e.classList.toggle('bar');
}
root.offsetTop;
for (let e of leaf_nodes) {
e.classList.toggle('bar');
}
root.offsetTop;
}
});
</script>

View file

@ -0,0 +1,42 @@
<!DOCTYPE html>
<script src="../resources/runner.js"></script>
<script src="./resources/utils.js"></script>
<div id=container></div>
<div id=root class=myscope></div>
<script>
const SELECTORS = 2000;
let style = document.createElement('style');
function makeStyle() {
let selectors = [...Array(SELECTORS).keys()].map(x => `.a${x}`);
// Creates a selector list which is expensive to evaluate:
// (.a1, .a2, .a3 ... .a<n-1>, .myscope)
return `
@scope (${selectors.join(',')}, .myscope) {
div {
margin: 1px;
}
}
`;
}
function setup() {
style.textContent = makeStyle();
createDOMTree(root, /* siblings */ 1, /* depth */ 50);
}
setup();
PerfTestRunner.measureTime({
description: 'Inserting @scope with a deep tree',
run: () => {
container.append(style);
root.offsetTop;
style.remove();
root.offsetTop;
}
});
</script>

View file

@ -0,0 +1,53 @@
<!DOCTYPE html>
<html>
<head>
<script src="../resources/runner.js"></script>
<style>
[attr=root] [attr=child] {}
</style>
</head>
<body>
<div id="root"></div>
<script>
function addChildren(element, numChildren, idPrefix)
{
for (var i = 0; i < numChildren; i++) {
var child = document.createElement("div");
child.id = idPrefix + i;
element.appendChild(child);
}
}
function makeTree(element, depth, fanOut, idPrefix)
{
if (depth <= 0)
return;
addChildren(element, fanOut, idPrefix);
for (var child = element.firstChild; child.nextSibling; child = child.nextSibling) {
makeTree(child, depth - 1, fanOut, child.id);
}
if (child)
makeTree(child, depth - 1, fanOut, child.id);
}
var root = document.querySelector("#root");
makeTree(root, 6, 5, "child");
var child = document.querySelector("#child012341");
child.setAttribute("attr", "child");
var runFunction = function()
{
root.offsetHeight; // force recalc style
root.setAttribute("attr" , "root");
root.offsetHeight;
root.removeAttribute("attr");
}
PerfTestRunner.measureRunsPerSecond({
description: "Measures performance of the CSS attribute descendant selector ([a=b] [c=d]).",
run: runFunction
});
</script>
</body>
</html>

View file

@ -0,0 +1,53 @@
<!DOCTYPE html>
<script src="../resources/runner.js"></script>
<style>
#container {
width: 200px;
}
.inline_size {
container-type: inline-size;
}
</style>
<div id=container>
<div id=target></div>
</div>
<style id=style></style>
<script>
// Makes a big container query as follows:
//
// @container ((width = 1000px) or (width = 1001px) or ... (width = (1000+n)px) or (width = 200px)) {
// #target {}
// #target {}
// ... n times in total ...
// #target {}
// }
function makeQuery(n) {
let expressions = [];
let rules = [];
for (let i = 0; i < n; i++) {
expressions.push(`(width = ${1000+i}px)`);
rules.push('#target { }');
}
expressions.push(`(width = 200px)`);
return `@container (${expressions.join(' or ')}) { ${rules.join('\n') } }`;
}
function setup() {
style.textContent = makeQuery(1000);
}
setup();
PerfTestRunner.measureTime({
description: 'Big container query with many inner rules',
run: () => {
target.offsetTop;
container.classList.toggle('inline_size');
target.offsetTop;
container.classList.toggle('inline_size');
}
});
</script>

View file

@ -0,0 +1,32 @@
<!DOCTYPE html>
<script src="../resources/runner.js"></script>
<style>
div {
counter-increment: my-counter;
}
div::before {
content: counter(my-counter);
}
</style>
<body></body>
<script>
function createTree(root, num_elements, depth) {
if (!depth) {
return;
}
for (let i = 0; i < num_elements; ++i) {
const div = document.createElement('div');
root.append(div);
createTree(div, num_elements, depth - 1);
}
}
PerfTestRunner.measureTime({
description: 'Measure the time of the css counters creation',
run: function() {
document.body.innerHTML = '';
createTree(document.body, 5, 6);
},
iterationCount: 5,
});
</script>

View file

@ -0,0 +1,40 @@
<!DOCTYPE html>
<script src="../resources/runner.js"></script>
<script src="resources/utils.js"></script>
<style>
body.default_ltr .default { direction: ltr; }
body.default_ltr .alternative { direction: rtl; }
body.default_rtl .default { direction: rtl; }
body.default_rtl .alternative { direction: ltr; }
div { margin-inline-start: 10px; }
/* Give the cascade something to do: */
div { border: 0px solid red; }
div { border: 0px solid green !important; }
div { border: 0px solid black; }
div { padding: 0px; }
</style>
<body class="default_ltr"></body>
<script>
function createTree(node, siblings, depth) {
if (!depth)
return;
for (let i = 0; i < siblings; i++) {
var div = document.createElement('div');
div.className = (depth % 2 == 0) ? 'default' : 'alternative';
node.append(div);
createTree(div, siblings, depth - 1);
}
}
createTree(document.body, 4, 6);
PerfTestRunner.measureTime({
description: 'Measure impact of switching direction with css-logical',
run: function() {
document.body.classList.toggle('default_ltr');
document.body.classList.toggle('default_rtl');
forceStyleRecalc(document.body);
}
});
</script>

View file

@ -0,0 +1,85 @@
<!DOCTYPE html>
<html>
<head>
<script src="../resources/runner.js"></script>
</head>
<body>
<div id="test"></div>
</body>
<script>
var div = document.getElementById("test");
var properties = {
'azimuth' : 'right',
'backgroundColor' : 'green',
'backgroundImage' : 'url(\'test.png\')',
'backgroundPosition' : 'top',
'backgroundRepeat' : 'repeat-x',
'background' : '#ffffff url(\'img_tree.png\') no-repeat right top',
'border' : '20px dotted red',
'borderBottomStyle' : 'dotted',
'borderCollapse' : 'separate',
'borderColor' : 'blue',
'borderSpacing' : '3px',
'borderStyle' : 'solid',
'borderTop' : 'green',
'borderWidth' : '20em',
'bottom' : '20%',
'captionSide' : 'top',
'clear' : 'both',
'clip' : 'rect(5px, 40px, 45px, 5px)',
'color' : 'red',
'content' : 'normal',
'direction' : 'rtl',
'display' : 'block',
'cssFloat' : 'right',
'fontFamily' : '"Times New Roman",Georgia,Serif',
'fontSize' : '13px',
'fontVariant' : 'small-caps',
'fontWeight' : '700',
'font' : 'italic bold 12px/30px Georgia, serif',
'height' : '200px',
'left' : '20%',
'letterSpacing' : '10px',
'lineHeight' : '40px',
'listStyleImage' : 'url(\'test.png\')',
'listStylePosition' : 'outside',
'listStyleType' : 'decimal',
'listStyle' : 'circle inside',
'marginRight' : '50px',
'margin' : '10px 20px 30px 5em',
'maxHeight' : '700px',
'maxWidth' : '300px',
'minHeight' : '100px',
'minWidth' : '100px',
'outlineColor' : 'gray',
'outlineStyle' : 'dotted',
'outlineWidth' : '5px',
'paddingTop' : '30px',
'padding' : '30px 20px 10px 50px',
'pageBreakAfter' : 'always',
'pageBreakInside' : 'auto',
'pause' : '2s',
'position' : 'static',
'right' : '150px',
'textAlign' : 'center',
'textDecoration' : 'blink',
'textTransform' : 'capitalize',
'top' : '25%',
'verticalAlign' : 'text-bottom',
'visibility' : 'visible',
'width' : '300px',
'webkitTransform' : 'scale3d(0.5, 0.5, 0.5)',
'wordSpacing' : '40px',
};
PerfTestRunner.measureRunsPerSecond({
description: "Measures performance of the CSS style array index getter and setter (a = elem.style[b], elem.style[c] = d).",
run:function() {
for (key in properties) {
var value = div.style[key];
div.style[key] = "";
div.style[key] = properties[key];
}
}
});
</script>
</html>

View file

@ -0,0 +1,85 @@
<!DOCTYPE html>
<html>
<head>
<script src="../resources/runner.js"></script>
</head>
<body>
<div id="test"></div>
</body>
<script>
var div = document.getElementById("test");
var properties = {
'azimuth' : 'right',
'background-color' : 'green',
'background-image' : 'url(\'test.png\')',
'background-position' : 'top',
'background-repeat' : 'repeat-x',
'background' : '#ffffff url(\'img_tree.png\') no-repeat right top',
'border' : '20px dotted red',
'border-bottom-style' : 'dotted',
'border-collapse' : 'separate',
'border-color' : 'blue',
'border-spacing' : '3px',
'border-style' : 'solid',
'border-top' : 'green',
'border-width' : '20em',
'bottom' : '20%',
'caption-side' : 'top',
'clear' : 'both',
'clip' : 'rect(5px, 40px, 45px, 5px)',
'color' : 'red',
'content' : 'normal',
'direction' : 'rtl',
'display' : 'block',
'css-float' : 'right',
'font-family' : '"Times New Roman",Georgia,Serif',
'font-size' : '13px',
'font-variant' : 'small-caps',
'font-weight' : '700',
'font' : 'italic bold 12px/30px Georgia, serif',
'height' : '200px',
'left' : '20%',
'letter-spacing' : '10px',
'line-height' : '40px',
'list-style-image' : 'url(\'test.png\')',
'list-style-position' : 'outside',
'list-style-type' : 'decimal',
'list-style' : 'circle inside',
'margin-right' : '50px',
'margin' : '10px 20px 30px 5em',
'max-height' : '700px',
'max-width' : '300px',
'min-height' : '100px',
'min-width' : '100px',
'outline-color' : 'gray',
'outline-style' : 'dotted',
'outline-width' : '5px',
'padding-top' : '30px',
'padding' : '30px 20px 10px 50px',
'page-break-after' : 'always',
'page-break-inside' : 'auto',
'pause' : '2s',
'position' : 'static',
'right' : '150px',
'text-align' : 'center',
'text-decoration' : 'blink',
'text-transform' : 'capitalize',
'top' : '25%',
'vertical-align' : 'text-bottom',
'visibility' : 'visible',
'width' : '300px',
'webkit-transform' : 'scale3d(0.5, 0.5, 0.5)',
'word-spacing' : '40px',
};
PerfTestRunner.measureRunsPerSecond({
description: "Measures performance of the CSS style getter and setter methods (elem.style.(getPropertyValue|removeProperty|setProperty)).",
run:function() {
for (key in properties) {
var value = div.style.getPropertyValue(key);
div.style.removeProperty(key);
div.style.setProperty(key, properties[key]);
}
}
});
</script>
</html>

View file

@ -0,0 +1,83 @@
<!DOCTYPE html>
<html>
<head>
<script src="../resources/runner.js"></script>
</head>
<body>
<div id="test"></div>
</body>
<script>
var div = document.getElementById("test");
var properties = {
'azimuth' : 'right',
'backgroundColor' : 'green',
'backgroundImage' : 'url(\'test.png\')',
'backgroundPosition' : 'top',
'backgroundRepeat' : 'repeat-x',
'background' : '#ffffff url(\'img_tree.png\') no-repeat right top',
'border' : '20px dotted red',
'borderBottomStyle' : 'dotted',
'borderCollapse' : 'separate',
'borderColor' : 'blue',
'borderSpacing' : '3px',
'borderStyle' : 'solid',
'borderTop' : 'green',
'borderWidth' : '20em',
'bottom' : '20%',
'captionSide' : 'top',
'clear' : 'both',
'clip' : 'rect(5px, 40px, 45px, 5px)',
'color' : 'red',
'content' : 'normal',
'direction' : 'rtl',
'display' : 'block',
'cssFloat' : 'right',
'fontFamily' : '"Times New Roman",Georgia,Serif',
'fontSize' : '13px',
'fontVariant' : 'small-caps',
'fontWeight' : '700',
'font' : 'italic bold 12px/30px Georgia, serif',
'height' : '200px',
'left' : '20%',
'letterSpacing' : '10px',
'lineHeight' : '40px',
'listStyleImage' : 'url(\'test.png\')',
'listStylePosition' : 'outside',
'listStyleType' : 'decimal',
'listStyle' : 'circle inside',
'marginRight' : '50px',
'margin' : '10px 20px 30px 5em',
'maxHeight' : '700px',
'maxWidth' : '300px',
'minHeight' : '100px',
'minWidth' : '100px',
'outlineColor' : 'gray',
'outlineStyle' : 'dotted',
'outlineWidth' : '5px',
'paddingTop' : '30px',
'padding' : '30px 20px 10px 50px',
'pageBreakAfter' : 'always',
'pageBreakInside' : 'auto',
'pause' : '2s',
'position' : 'static',
'right' : '150px',
'textAlign' : 'center',
'textDecoration' : 'blink',
'textTransform' : 'capitalize',
'top' : '25%',
'verticalAlign' : 'text-bottom',
'visibility' : 'visible',
'width' : '300px',
'webkitTransform' : 'scale3d(0.5, 0.5, 0.5)',
'wordSpacing' : '40px',
};
// The first run will just add the properties but it's fine as the first run of the benchmark is always ignored.
PerfTestRunner.measureRunsPerSecond({
description: "Measures performance of the CSS style array index setter (elem.style[a] = b).",
run:function() {
for (key in properties)
div.style[key] = properties[key];
}
});
</script>
</html>

View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<script src="../resources/runner.js"></script>
<style>
div {
quotes: "A" "Z";
}
div::before {
content: open-quote;
}
div::after {
content: close-quote;
}
</style>
<body></body>
<script>
function createTree(root, num_elements, depth) {
if (!depth) {
return;
}
for (let i = 0; i < num_elements; ++i) {
const div = document.createElement('div');
root.append(div);
createTree(div, num_elements, depth - 1);
}
}
PerfTestRunner.measureTime({
description: 'Measure the time of the css quotes creation',
run: function() {
document.body.innerHTML = '';
createTree(document.body, 5, 6);
},
iterationCount: 5,
});
</script>

View file

@ -0,0 +1,98 @@
<!DOCTYPE html>
<head>
<title>CSS Custom Properties and Variables: Changes that require resolving variable references</title>
<script src="../resources/runner.js"></script>
<script src="resources/utils.js"></script>
</head>
<style>
.container > div {
display: inline-block;
height: 14px;
width: 14px;
box-sizing: border-box;
border: 1px solid green;
}
.container {
height: 0px;
overflow: hidden;
}
</style>
<body>
<header id=info>CSS Variables: <button id=button></button></header>
<script>
const NUM_ELEMENTS = 20000;
const PROP_COUNT = 1000;
let curBorder = -1;
let root = document.createElement('div');
root.classList.add(`container`);
// Add ?ref to URL to run a similar test without CSS Variables.
const ref = document.location.href.endsWith('?ref');
button.textContent = ref ? 'OFF' : 'ON';
button.addEventListener('click', function(){
let href = document.location.href;
if (ref) {
document.location.href = href.substr(0, href.length - 4);
} else {
document.location.href = href + '?ref';
}
});
function hexcolor(i) {
let hex = i.toString(16);
while (hex.length < 6)
hex = '0' + hex;
return '#' + hex;
}
function createDOMTree() {
for (let n = 0; n < NUM_ELEMENTS; n++) {
let div = document.createElement('div');
let i = n % PROP_COUNT;
div.classList.add(`bg-color${i}`);
root.appendChild(div);
}
document.body.appendChild(root);
}
function createDivRules() {
let lines = [];
for (let i = 0; i < PROP_COUNT; i++) {
lines.push(`.border${i} > div { border-color: ${hexcolor(i)}; }`);
if (ref)
lines.push(`.bg-color${i} { background-color: ${hexcolor(i)}; }`);
else
lines.push(`.bg-color${i} { background-color: var(--prop-${i}); }`);
}
return lines.join('\n');
}
// Create a rule which defines 'propCount' custom properties at :root.
function createRootRule() {
if (ref)
return;
let lines = [':root {'];
for (let i = 0; i < PROP_COUNT; i++) {
lines.push(`--prop-${i}: ${hexcolor(i)};`);
}
lines.push('}');
return lines.join('\n');
}
applyCSSRule(createDivRules());
applyCSSRule(createRootRule());
createDOMTree();
PerfTestRunner.measureTime({
description: "Measures the performance of the CSS variable reference recalc.",
setup: () => {
root.classList.remove(`border${curBorder}`);
// Using PROP_COUNT to ensure different border values, avoiding the style cache
curBorder = (curBorder + 1) % PROP_COUNT;
},
run: function() {
root.classList.add(`border${curBorder}`);
forceStyleRecalc(document.body);
},
});
</script>
</body>

View file

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<script src="../resources/runner.js"></script>
<script src="resources/utils.js"></script>
</head>
<body>
<script>
createRegularDOMTree();
var allElements = document.body.getElementsByTagName("div");
for (var i = 0; i < allElements.length; ++i) {
if (i % 2 == 0) {
allElements[i].className = "a";
} else {
allElements[i].className = "b";
}
}
PerfTestRunner.measureTime({
description: "Measures the performance of a child class selector.",
run: function() {
var rule = applyCSSRule(".a > .b { cursor: crosshair; }");
forceStyleRecalc(document.body);
rule.remove();
forceStyleRecalc(document.body);
},
tracingCategories: 'blink',
traceEventsToMeasure: [
'Document::updateStyle',
'Document::recalcStyle',
'Document::rebuildLayoutTree'
]
});
</script>
</body>
</html>

View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<script src="../resources/runner.js"></script>
<script src="resources/utils.js"></script>
</head>
<body>
</body>
<script>
createRegularDOMTree();
PerfTestRunner.measureTime({
description: "Measures the performance of applying a style on the div child of a div.",
run: function() {
var rule = applyCSSRule("div div { cursor: crosshair; }");
forceStyleRecalc(document.body);
rule.remove();
forceStyleRecalc(document.body);
},
tracingCategories: 'blink',
traceEventsToMeasure: [
'Document::updateStyle',
'Document::recalcStyle',
'Document::rebuildLayoutTree'
]
});
</script>
</html>

View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<head>
<title>CSS Custom Properties and Variables: Changes in property's declaration</title>
<script src="../resources/runner.js"></script>
<script src="resources/utils.js"></script>
</head>
<style>
.crosshair { --prop: crosshair; }
.default { --prop: default; }
body > div > div { background-color: grey; }
</style>
<body>
<script>
function createDOMTree() {
let div = document.createElement('div');
div.innerHTML = '<div><div><div><div><div style="cursor: var(--prop)">' + '' + '</div></div></div></div></div>';
for (let i = 0; i < 10000; i++) {
document.body.appendChild(div.cloneNode(true));
}
}
createDOMTree();
var theme;
PerfTestRunner.measureTime({
description: "Measures the performance in the propagation of a custom property declaration.",
setup: () => {
document.body.classList.remove(theme);
theme = theme == 'crosshair' ? 'default' : 'crosshair';
},
run: function() {
document.body.classList.add(theme);
forceStyleRecalc(document.body);
},
});
</script>
</body>

View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<script src="../resources/runner.js"></script>
<script src="resources/utils.js"></script>
</head>
<body>
</body>
<script>
createRegularDOMTree();
PerfTestRunner.measureTime({
description: "Measures the performance of applying a style on all divs.",
run: function() {
var rule = applyCSSRule("div { cursor: crosshair; }");
forceStyleRecalc(document.body);
rule.remove();
forceStyleRecalc(document.body);
},
tracingCategories: 'blink',
traceEventsToMeasure: [
'Document::updateStyle',
'Document::recalcStyle',
'Document::rebuildLayoutTree'
]
});
</script>
</html>

View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<script src="../resources/runner.js"></script>
<script src="resources/utils.js"></script>
</head>
<body>
</body>
<script>
createRegularDOMTree();
PerfTestRunner.measureTime({
description: "Measures the performance of applying a style on the div grandchild of a div.",
run: function() {
var rule = applyCSSRule("div div div { cursor: crosshair; }");
forceStyleRecalc(document.body);
rule.remove();
forceStyleRecalc(document.body);
},
tracingCategories: 'blink',
traceEventsToMeasure: [
'Document::updateStyle',
'Document::recalcStyle',
'Document::rebuildLayoutTree'
]
});
</script>
</html>

View file

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<script src="../resources/runner.js"></script>
<script src="resources/utils.js"></script>
</head>
<body>
<script>
createRegularDOMTree();
var allElements = document.body.getElementsByTagName("div");
for (var i = 0; i < allElements.length; ++i) {
allElements[i].className = "a b";
}
PerfTestRunner.measureTime({
description: "Measures the performance of multiple class selectors.",
run: function() {
var rule = applyCSSRule(".a .b { cursor: crosshair; }");
forceStyleRecalc(document.body);
rule.remove();
forceStyleRecalc(document.body);
},
tracingCategories: 'blink',
traceEventsToMeasure: [
'Document::updateStyle',
'Document::recalcStyle',
'Document::rebuildLayoutTree'
]
});
</script>
</body>
</html>

View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
<script src="../resources/runner.js"></script>
<script src="resources/utils.js"></script>
</head>
<body>
</body>
<script>
createRegularDOMTree();
var allElements = document.body.getElementsByTagName("div");
for (var i = 0; i < allElements.length; ++i) {
if (i % 2 == 0)
allElements[i].dataset.a = "foo";
else
allElements[i].dataset.b = "bar";
}
PerfTestRunner.measureTime({
description: "Measures the performance of an qualified data attribute selector with a value.",
run: function() {
var rule = applyCSSRule("div[data-a=\"foo\"] div[data-b=\"bar\"] { cursor: crosshair; }");
forceStyleRecalc(document.body);
rule.remove();
forceStyleRecalc(document.body);
},
tracingCategories: 'blink',
traceEventsToMeasure: [
'Document::updateStyle',
'Document::recalcStyle',
'Document::rebuildLayoutTree'
]
});
</script>
</html>

View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<script src="../resources/runner.js"></script>
<script src="resources/utils.js"></script>
</head>
<body>
</body>
<script>
createDOMTree(document.body, 3, 3);
PerfTestRunner.measureTime({
description: "Measures the performance of a solo pseudo selector applied on a grandchild of a div.",
run: function() {
var rule = applyCSSRule("div div div:after { content: 'after'; }");
forceStyleRecalc(document.body);
rule.remove();
forceStyleRecalc(document.body);
},
tracingCategories: 'blink',
traceEventsToMeasure: [
'Document::updateStyle',
'Document::recalcStyle',
'Document::rebuildLayoutTree'
]
});
</script>
</html>

View file

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<script src="../resources/runner.js"></script>
<script src="resources/utils.js"></script>
</head>
<style id="sheet">
.c { cursor: crosshair; }
</style>
<body>
<script>
createDOMTree(document.body, 6, 6);
var allElements = document.body.getElementsByTagName("div");
for (var i = 0; i < allElements.length; ++i) {
allElements[i].className = 'c';
}
PerfTestRunner.measureTime({
description: "Measures the performance of inserting/deleting a new rule into an existing stylesheet.",
run: function() {
let sheet = document.getElementById('sheet').sheet;
sheet.insertRule(".doesnotexist { color: red; }", 1);
forceStyleRecalc(document.body);
sheet.deleteRule(1);
forceStyleRecalc(document.body);
},
tracingCategories: 'blink',
traceEventsToMeasure: [
'Document::updateStyle',
'Document::recalcStyle',
'Document::rebuildLayoutTree'
]
});
</script>
</body>
</html>

View file

@ -0,0 +1,27 @@
<!DOCTYPE html>
<html>
<head>
<script src="../resources/runner.js"></script>
<script src="resources/utils.js"></script>
</head>
<body>
</body>
<script>
createRegularDOMTree();
PerfTestRunner.measureTime({
description: "Measures the performance of a pair of nth-child selectors.",
run: function() {
var rule = applyCSSRule("div:nth-child(1) div:nth-child(1) div { cursor: crosshair; }");
forceStyleRecalc(document.body);
rule.remove();
forceStyleRecalc(document.body);
},
tracingCategories: 'blink',
traceEventsToMeasure: [
'Document::updateStyle',
'Document::recalcStyle',
'Document::rebuildLayoutTree'
]
});
</script>
</html>

View file

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html>
<head>
<script src="../resources/runner.js"></script>
<script src="resources/utils.js"></script>
</head>
<body>
</body>
<script>
createRegularDOMTree();
var allElements = document.body.getElementsByTagName("div");
for (var i=0; i < allElements.length; i+=2) {
allElements[i].className = "wrap";
}
PerfTestRunner.measureTime({
description: "Measures the performance of partial attribute matching.",
run: function() {
var rule = applyCSSRule("[class^='wrap'] { cursor: crosshair; }");
forceStyleRecalc(document.body);
rule.remove();
forceStyleRecalc(document.body);
},
tracingCategories: 'blink',
traceEventsToMeasure: [
'Document::updateStyle',
'Document::recalcStyle',
'Document::rebuildLayoutTree'
]
});
</script>
</html>

View file

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html>
<head>
<script src="../resources/runner.js"></script>
<script src="resources/utils.js"></script>
</head>
<body>
</body>
<script>
createRegularDOMTree();
var allElements = document.body.getElementsByTagName("div");
for (var i = 0; i < allElements.length; ++i) {
allElements[i].dataset.test = "foo";
}
PerfTestRunner.measureTime({
description: "Measures the performance of a qualified data attribute selector.",
run: function() {
var rule = applyCSSRule("div[data-test] { cursor: crosshair; }");
forceStyleRecalc(document.body);
rule.remove();
forceStyleRecalc(document.body);
},
tracingCategories: 'blink',
traceEventsToMeasure: [
'Document::updateStyle',
'Document::recalcStyle',
'Document::rebuildLayoutTree'
]
});
</script>
</html>

Some files were not shown because too many files have changed in this diff Show more