summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/js-self-profiling/resources
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /testing/web-platform/tests/js-self-profiling/resources
parentInitial commit. (diff)
downloadfirefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz
firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'testing/web-platform/tests/js-self-profiling/resources')
-rw-r--r--testing/web-platform/tests/js-self-profiling/resources/__dir__.headers1
-rw-r--r--testing/web-platform/tests/js-self-profiling/resources/child-frame.html8
-rw-r--r--testing/web-platform/tests/js-self-profiling/resources/external-script.js9
-rw-r--r--testing/web-platform/tests/js-self-profiling/resources/external-script.js.headers1
-rw-r--r--testing/web-platform/tests/js-self-profiling/resources/profile-utils.js149
-rw-r--r--testing/web-platform/tests/js-self-profiling/resources/profiling-script.js26
-rw-r--r--testing/web-platform/tests/js-self-profiling/resources/profiling-script.js.headers1
7 files changed, 195 insertions, 0 deletions
diff --git a/testing/web-platform/tests/js-self-profiling/resources/__dir__.headers b/testing/web-platform/tests/js-self-profiling/resources/__dir__.headers
new file mode 100644
index 0000000000..93537b44de
--- /dev/null
+++ b/testing/web-platform/tests/js-self-profiling/resources/__dir__.headers
@@ -0,0 +1 @@
+Document-Policy: js-profiling
diff --git a/testing/web-platform/tests/js-self-profiling/resources/child-frame.html b/testing/web-platform/tests/js-self-profiling/resources/child-frame.html
new file mode 100644
index 0000000000..7f8125eae7
--- /dev/null
+++ b/testing/web-platform/tests/js-self-profiling/resources/child-frame.html
@@ -0,0 +1,8 @@
+<!DOCTYPE html>
+<html>
+<head>
+</head>
+<body>
+ <script src="profile-utils.js"></script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/js-self-profiling/resources/external-script.js b/testing/web-platform/tests/js-self-profiling/resources/external-script.js
new file mode 100644
index 0000000000..6f6bd42b25
--- /dev/null
+++ b/testing/web-platform/tests/js-self-profiling/resources/external-script.js
@@ -0,0 +1,9 @@
+// NOTE: Modifying the location of functions in this file will cause
+// `external-script.html` to fail! Please update the following constants
+// accordingly.
+const EXTERNAL_SCRIPT_FUNCTION_LINE = 7;
+const EXTERNAL_SCRIPT_FUNCTION_COLUMN = 32;
+
+function externalScriptFunction(sample) {
+ sample();
+}
diff --git a/testing/web-platform/tests/js-self-profiling/resources/external-script.js.headers b/testing/web-platform/tests/js-self-profiling/resources/external-script.js.headers
new file mode 100644
index 0000000000..cb762eff80
--- /dev/null
+++ b/testing/web-platform/tests/js-self-profiling/resources/external-script.js.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *
diff --git a/testing/web-platform/tests/js-self-profiling/resources/profile-utils.js b/testing/web-platform/tests/js-self-profiling/resources/profile-utils.js
new file mode 100644
index 0000000000..2c32f34608
--- /dev/null
+++ b/testing/web-platform/tests/js-self-profiling/resources/profile-utils.js
@@ -0,0 +1,149 @@
+(function(global) {
+ const TEST_SAMPLE_INTERVAL = 10;
+ const ENSURE_SAMPLE_SPIN_WAIT_MS = 500;
+
+ function forceSample() {
+ // Spin for |TEST_SAMPLE_INTERVAL + 500|ms to ensure that a sample occurs
+ // before this function returns. As periodic sampling is enforced by a
+ // SHOULD clause, it is indeed testable.
+ //
+ // More reliable sampling will be handled in a future testdriver RFC
+ // (https://github.com/web-platform-tests/rfcs/pull/81).
+ for (const deadline = performance.now() + TEST_SAMPLE_INTERVAL +
+ ENSURE_SAMPLE_SPIN_WAIT_MS;
+ performance.now() < deadline;)
+ ;
+ }
+
+ // Creates a new profile that captures the execution of when the given
+ // function calls the `sample` function passed to it.
+ async function profileFunction(func) {
+ const profiler = new Profiler({
+ sampleInterval: TEST_SAMPLE_INTERVAL,
+ maxBufferSize: Number.MAX_SAFE_INTEGER,
+ });
+
+ func(() => forceSample());
+
+ const trace = await profiler.stop();
+
+ // Sanity check ensuring that we captured a sample.
+ assert_greater_than(trace.resources.length, 0);
+ assert_greater_than(trace.frames.length, 0);
+ assert_greater_than(trace.stacks.length, 0);
+ assert_greater_than(trace.samples.length, 0);
+
+ return trace;
+ }
+
+ async function testFunction(func, frame) {
+ const trace = await profileFunction(func);
+ assert_true(containsFrame(trace, frame), 'trace contains frame');
+ }
+
+ function substackMatches(trace, stackId, expectedStack) {
+ if (expectedStack.length === 0) {
+ return true;
+ }
+ if (stackId === undefined) {
+ return false;
+ }
+
+ const stackElem = trace.stacks[stackId];
+ const expectedFrame = expectedStack[0];
+
+ if (!frameMatches(trace.frames[stackElem.frameId], expectedFrame)) {
+ return false;
+ }
+ return substackMatches(trace, stackElem.parentId, expectedStack.slice(1));
+ }
+
+ // Returns true if the trace contains a frame matching the given specification.
+ // We define a "match" as follows: a frame A matches an expectation E if (and
+ // only if) for each field of E, A has the same value.
+ function containsFrame(trace, expectedFrame) {
+ return trace.frames.find(frame => {
+ return frameMatches(frame, expectedFrame);
+ }) !== undefined;
+ }
+
+ // Returns true if a trace contains a substack in one of its samples, ordered
+ // leaf to root.
+ function containsSubstack(trace, expectedStack) {
+ return trace.samples.find(sample => {
+ let stackId = sample.stackId;
+ while (stackId !== undefined) {
+ if (substackMatches(trace, stackId, expectedStack)) {
+ return true;
+ }
+ stackId = trace.stacks[stackId].parentId;
+ }
+ return false;
+ }) !== undefined;
+ }
+
+ function containsResource(trace, expectedResource) {
+ return trace.resources.includes(expectedResource);
+ }
+
+ // Returns true if a trace contains a sample matching the given specification.
+ // We define a "match" as follows: a sample A matches an expectation E if (and
+ // only if) for each field of E, A has the same value.
+ function containsSample(trace, expectedSample) {
+ return trace.samples.find(sample => {
+ return sampleMatches(sample, expectedSample);
+ }) !== undefined;
+ }
+
+ // Compares each set field of `expected` against the given frame `actual`.
+ function sampleMatches(actual, expected) {
+ return (expected.timestamp === undefined ||
+ expected.timestamp === actual.timestamp) &&
+ (expected.stackId === undefined ||
+ expected.stackId === actual.stackId) &&
+ (expected.marker === undefined || expected.marker === actual.marker);
+ }
+
+ // Compares each set field of `expected` against the given frame `actual`.
+ function frameMatches(actual, expected) {
+ return (expected.name === undefined || expected.name === actual.name) &&
+ (expected.resourceId === undefined || expected.resourceId === actual.resourceId) &&
+ (expected.line === undefined || expected.line === actual.line) &&
+ (expected.column === undefined || expected.column === actual.column);
+ }
+
+ function forceSampleFrame(frame) {
+ const channel = new MessageChannel();
+ const replyPromise = new Promise(res => {
+ channel.port1.onmessage = res;
+ });
+ frame.postMessage('', '*', [channel.port2]);
+ return replyPromise;
+ }
+
+ window.addEventListener('message', message => {
+ // Force sample in response to messages received.
+ (function sampleFromMessage() {
+ ProfileUtils.forceSample();
+ message.ports[0].postMessage('');
+ })();
+ });
+
+ global.ProfileUtils = {
+ // Capturing
+ profileFunction,
+ forceSample,
+
+ // Containment checks
+ containsFrame,
+ containsSubstack,
+ containsResource,
+ containsSample,
+
+ // Cross-frame sampling
+ forceSampleFrame,
+
+ // Assertions
+ testFunction,
+ };
+})(this);
diff --git a/testing/web-platform/tests/js-self-profiling/resources/profiling-script.js b/testing/web-platform/tests/js-self-profiling/resources/profiling-script.js
new file mode 100644
index 0000000000..9f09e05b34
--- /dev/null
+++ b/testing/web-platform/tests/js-self-profiling/resources/profiling-script.js
@@ -0,0 +1,26 @@
+(function(global) {
+ let counter = 0;
+
+ // Spins up a new profiler and performs some work in a new top-level task,
+ // calling some builtins. Returns a promise for the resulting trace.
+ const profileBuiltinsInNewTask = () => {
+ // Run profiling logic in a new task to eliminate the caller stack.
+ return new Promise(resolve => {
+ setTimeout(async () => {
+ const profiler = new Profiler({ sampleInterval: 10, maxBufferSize: 10000 });
+ for (const deadline = performance.now() + 500; performance.now() < deadline;) {
+ // Run a range of builtins to ensure they get included in the trace.
+ // Store this computation in a variable to prevent getting optimized out.
+ counter += Math.random();
+ counter += performance.now();
+ }
+ const trace = await profiler.stop();
+ resolve(trace);
+ });
+ });
+ }
+
+ global.ProfilingScript = {
+ profileBuiltinsInNewTask,
+ }
+})(window);
diff --git a/testing/web-platform/tests/js-self-profiling/resources/profiling-script.js.headers b/testing/web-platform/tests/js-self-profiling/resources/profiling-script.js.headers
new file mode 100644
index 0000000000..cb762eff80
--- /dev/null
+++ b/testing/web-platform/tests/js-self-profiling/resources/profiling-script.js.headers
@@ -0,0 +1 @@
+Access-Control-Allow-Origin: *