Skip to content

Commit d979723

Browse files
Async Runner with Message Channel (#458)
1 parent d6b5ffe commit d979723

18 files changed

+147
-48
lines changed

resources/benchmark-runner.mjs

+2-1
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,8 @@ export class BenchmarkRunner {
409409
async runSuite(suite) {
410410
// FIXME: Encapsulate more state in the SuiteRunner.
411411
// FIXME: Return and use measured values from SuiteRunner.
412-
const suiteRunnerClass = SUITE_RUNNER_LOOKUP[suite.type ?? "default"];
412+
const type = suite.type ?? ((params.useAsyncSteps && "async") || "default");
413+
const suiteRunnerClass = SUITE_RUNNER_LOOKUP[type];
413414
const suiteRunner = new suiteRunnerClass(this._frame, this._page, params, suite, this._client, this._measuredValues);
414415
await suiteRunner.run();
415416
}

resources/developer-mode.mjs

+8-1
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export function createDeveloperModeContainer() {
2121
settings.append(createUIForWarmupSuite());
2222
settings.append(createUIForWarmupBeforeSync());
2323
settings.append(createUIForSyncStepDelay());
24+
settings.append(createUIForAsyncSteps());
2425

2526
content.append(document.createElement("hr"));
2627
content.append(settings);
@@ -45,6 +46,12 @@ function createUIForWarmupSuite() {
4546
});
4647
}
4748

49+
function createUIForAsyncSteps() {
50+
return createCheckboxUI("Use Async Steps", params.useAsyncSteps, (isChecked) => {
51+
params.useAsyncSteps = isChecked;
52+
});
53+
}
54+
4855
function createCheckboxUI(labelValue, initialValue, paramsUpdateCallback) {
4956
const checkbox = document.createElement("input");
5057
checkbox.type = "checkbox";
@@ -255,7 +262,7 @@ function updateURL() {
255262
}
256263
}
257264

258-
const defaultParamKeys = ["iterationCount", "useWarmupSuite", "warmupBeforeSync", "waitBeforeSync"];
265+
const defaultParamKeys = ["iterationCount", "useWarmupSuite", "warmupBeforeSync", "waitBeforeSync", "useAsyncSteps"];
259266
for (const paramKey of defaultParamKeys) {
260267
if (params[paramKey] !== defaultParams[paramKey])
261268
url.searchParams.set(paramKey, params[paramKey]);
+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="./_next/static/css/a0dca1379a01e5cf.css" as="style"/><link rel="stylesheet" href="./_next/static/css/a0dca1379a01e5cf.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="./_next/static/chunks/webpack-e50e9853db18b759.js" defer=""></script><script src="./_next/static/chunks/framework-2c79e2a64abdb08b.js" defer=""></script><script src="./_next/static/chunks/main-2ba37e62325cc71b.js" defer=""></script><script src="./_next/static/chunks/pages/_app-4fe6038a10d156ec.js" defer=""></script><script src="./_next/static/chunks/pages/_error-54de1933a164a1ff.js" defer=""></script><script src="./_next/static/slmX88Sy3MO0SLK8cVHnz/_buildManifest.js" defer=""></script><script src="./_next/static/slmX88Sy3MO0SLK8cVHnz/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><div id="settings-container"></div><div id="notifications-container"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"slmX88Sy3MO0SLK8cVHnz","assetPrefix":".","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>
1+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="./_next/static/css/a0dca1379a01e5cf.css" as="style"/><link rel="stylesheet" href="./_next/static/css/a0dca1379a01e5cf.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="./_next/static/chunks/webpack-e50e9853db18b759.js" defer=""></script><script src="./_next/static/chunks/framework-2c79e2a64abdb08b.js" defer=""></script><script src="./_next/static/chunks/main-2ba37e62325cc71b.js" defer=""></script><script src="./_next/static/chunks/pages/_app-77983e68be50f72a.js" defer=""></script><script src="./_next/static/chunks/pages/_error-54de1933a164a1ff.js" defer=""></script><script src="./_next/static/dKI4-ZnFPRMFEw-AlcuLr/_buildManifest.js" defer=""></script><script src="./_next/static/dKI4-ZnFPRMFEw-AlcuLr/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><div id="settings-container"></div><div id="notifications-container"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{"statusCode":404}},"page":"/_error","query":{},"buildId":"dKI4-ZnFPRMFEw-AlcuLr","assetPrefix":".","nextExport":true,"isFallback":false,"gip":true,"scriptLoader":[]}</script></body></html>

resources/newssite/news-next/dist/_next/static/chunks/553-29fd8c03a09c7b37.js

-32
This file was deleted.

resources/newssite/news-next/dist/_next/static/chunks/743-fd706aeabb7828e3.js

+32
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/newssite/news-next/dist/_next/static/chunks/pages/_app-4fe6038a10d156ec.js resources/newssite/news-next/dist/_next/static/chunks/pages/_app-77983e68be50f72a.js

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/newssite/news-next/dist/_next/static/chunks/pages/index-5268ea812327eb5e.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/newssite/news-next/dist/_next/static/chunks/pages/index-7052462c4e106c39.js

-1
This file was deleted.

resources/newssite/news-next/dist/_next/static/css/2cf5163b53bb0adb.css

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/newssite/news-next/dist/_next/static/css/69253d842fd3fbfd.css

-1
This file was deleted.

resources/newssite/news-next/dist/_next/static/dKI4-ZnFPRMFEw-AlcuLr/_buildManifest.js

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

resources/newssite/news-next/dist/_next/static/slmX88Sy3MO0SLK8cVHnz/_buildManifest.js

-1
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="./_next/static/css/a0dca1379a01e5cf.css" as="style"/><link rel="stylesheet" href="./_next/static/css/a0dca1379a01e5cf.css" data-n-g=""/><link rel="preload" href="./_next/static/css/69253d842fd3fbfd.css" as="style"/><link rel="stylesheet" href="./_next/static/css/69253d842fd3fbfd.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="./_next/static/chunks/webpack-e50e9853db18b759.js" defer=""></script><script src="./_next/static/chunks/framework-2c79e2a64abdb08b.js" defer=""></script><script src="./_next/static/chunks/main-2ba37e62325cc71b.js" defer=""></script><script src="./_next/static/chunks/pages/_app-4fe6038a10d156ec.js" defer=""></script><script src="./_next/static/chunks/553-29fd8c03a09c7b37.js" defer=""></script><script src="./_next/static/chunks/pages/index-7052462c4e106c39.js" defer=""></script><script src="./_next/static/slmX88Sy3MO0SLK8cVHnz/_buildManifest.js" defer=""></script><script src="./_next/static/slmX88Sy3MO0SLK8cVHnz/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><div id="settings-container"></div><div id="notifications-container"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/","query":{},"buildId":"slmX88Sy3MO0SLK8cVHnz","assetPrefix":".","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
1+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link rel="preload" href="./_next/static/css/a0dca1379a01e5cf.css" as="style"/><link rel="stylesheet" href="./_next/static/css/a0dca1379a01e5cf.css" data-n-g=""/><link rel="preload" href="./_next/static/css/2cf5163b53bb0adb.css" as="style"/><link rel="stylesheet" href="./_next/static/css/2cf5163b53bb0adb.css" data-n-p=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="./_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"></script><script src="./_next/static/chunks/webpack-e50e9853db18b759.js" defer=""></script><script src="./_next/static/chunks/framework-2c79e2a64abdb08b.js" defer=""></script><script src="./_next/static/chunks/main-2ba37e62325cc71b.js" defer=""></script><script src="./_next/static/chunks/pages/_app-77983e68be50f72a.js" defer=""></script><script src="./_next/static/chunks/743-fd706aeabb7828e3.js" defer=""></script><script src="./_next/static/chunks/pages/index-5268ea812327eb5e.js" defer=""></script><script src="./_next/static/dKI4-ZnFPRMFEw-AlcuLr/_buildManifest.js" defer=""></script><script src="./_next/static/dKI4-ZnFPRMFEw-AlcuLr/_ssgManifest.js" defer=""></script></head><body><div id="__next"></div><div id="settings-container"></div><div id="notifications-container"></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/","query":{},"buildId":"dKI4-ZnFPRMFEw-AlcuLr","assetPrefix":".","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>

resources/shared/params.mjs

+3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ export class Params {
1212
tags = [];
1313
// Toggle running a dummy suite once before the normal test suites.
1414
useWarmupSuite = false;
15+
// toggle async type vs default raf type.
16+
useAsyncSteps = false;
1517
// Change how a test measurement is triggered and async time is measured:
1618
// "timer": The classic (as in Speedometer 2.x) way using setTimeout
1719
// "raf": Using rAF callbacks, both for triggering the sync part and for measuring async time.
@@ -50,6 +52,7 @@ export class Params {
5052
this.tags = this._parseTags(searchParams);
5153
this.developerMode = this._parseBooleanParam(searchParams, "developerMode");
5254
this.useWarmupSuite = this._parseBooleanParam(searchParams, "useWarmupSuite");
55+
this.useAsyncSteps = this._parseBooleanParam(searchParams, "useAsyncSteps");
5356
this.waitBeforeSync = this._parseIntParam(searchParams, "waitBeforeSync", 0);
5457
this.warmupBeforeSync = this._parseIntParam(searchParams, "warmupBeforeSync", 0);
5558
this.measurementMethod = this._parseMeasurementMethod(searchParams);

resources/shared/test-invoker.mjs

+50-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ class TestInvoker {
77
}
88
}
99

10-
export class RAFTestInvoker extends TestInvoker {
10+
class BaseRAFTestInvoker extends TestInvoker {
1111
start() {
1212
return new Promise((resolve) => {
1313
if (this._params.waitBeforeSync)
@@ -16,7 +16,9 @@ export class RAFTestInvoker extends TestInvoker {
1616
this._scheduleCallbacks(resolve);
1717
});
1818
}
19+
}
1920

21+
class RAFTestInvoker extends BaseRAFTestInvoker {
2022
_scheduleCallbacks(resolve) {
2123
requestAnimationFrame(() => this._syncCallback());
2224
requestAnimationFrame(() => {
@@ -31,7 +33,54 @@ export class RAFTestInvoker extends TestInvoker {
3133
}
3234
}
3335

36+
class AsyncRAFTestInvoker extends BaseRAFTestInvoker {
37+
static mc = new MessageChannel();
38+
_scheduleCallbacks(resolve) {
39+
let gotTimer = false;
40+
let gotMessage = false;
41+
let gotPromise = false;
42+
43+
const tryTriggerAsyncCallback = () => {
44+
if (!gotTimer || !gotMessage || !gotPromise)
45+
return;
46+
47+
this._asyncCallback();
48+
setTimeout(async () => {
49+
await this._reportCallback();
50+
resolve();
51+
}, 0);
52+
};
53+
54+
requestAnimationFrame(async () => {
55+
await this._syncCallback();
56+
gotPromise = true;
57+
tryTriggerAsyncCallback();
58+
});
59+
60+
requestAnimationFrame(() => {
61+
setTimeout(async () => {
62+
await Promise.resolve();
63+
gotTimer = true;
64+
tryTriggerAsyncCallback();
65+
});
66+
67+
AsyncRAFTestInvoker.mc.port1.addEventListener(
68+
"message",
69+
async function () {
70+
await Promise.resolve();
71+
gotMessage = true;
72+
tryTriggerAsyncCallback();
73+
},
74+
{ once: true }
75+
);
76+
AsyncRAFTestInvoker.mc.port1.start();
77+
AsyncRAFTestInvoker.mc.port2.postMessage("speedometer");
78+
});
79+
}
80+
}
81+
3482
export const TEST_INVOKER_LOOKUP = {
3583
__proto__: null,
3684
raf: RAFTestInvoker,
85+
async: AsyncRAFTestInvoker,
3786
};

resources/shared/test-runner.mjs

+41-5
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,28 @@ export class TestRunner {
77
#suite;
88
#test;
99
#callback;
10+
#type;
1011

11-
constructor(frame, page, params, suite, test, callback) {
12+
constructor(frame, page, params, suite, test, callback, type) {
1213
this.#suite = suite;
1314
this.#test = test;
1415
this.#params = params;
1516
this.#callback = callback;
16-
1717
this.#page = page;
1818
this.#frame = frame;
19+
this.#type = type;
20+
}
21+
22+
get page() {
23+
return this.#page;
24+
}
25+
26+
get test() {
27+
return this.#test;
28+
}
29+
30+
_runSyncStep(test, page) {
31+
test.run(page);
1932
}
2033

2134
async runTest() {
@@ -30,7 +43,7 @@ export class TestRunner {
3043
let asyncStartTime;
3144
let asyncTime;
3245

33-
const runSync = () => {
46+
const runSync = async () => {
3447
if (this.#params.warmupBeforeSync) {
3548
performance.mark("warmup-start");
3649
const startTime = performance.now();
@@ -41,7 +54,12 @@ export class TestRunner {
4154
}
4255
performance.mark(syncStartLabel);
4356
const syncStartTime = performance.now();
44-
this.#test.run(this.#page);
57+
58+
if (this.#type === "async")
59+
await this._runSyncStep(this.test, this.page);
60+
else
61+
this._runSyncStep(this.test, this.page);
62+
4563
const mark = performance.mark(syncEndLabel);
4664
const syncEndTime = mark.startTime;
4765

@@ -68,9 +86,27 @@ export class TestRunner {
6886
};
6987

7088
const report = () => this.#callback(this.#test, syncTime, asyncTime);
71-
const invokerClass = TEST_INVOKER_LOOKUP[this.#params.measurementMethod];
89+
const invokerType = this.#suite.type === "async" || this.#params.useAsyncSteps ? "async" : this.#params.measurementMethod;
90+
const invokerClass = TEST_INVOKER_LOOKUP[invokerType];
7291
const invoker = new invokerClass(runSync, measureAsync, report, this.#params);
7392

7493
return invoker.start();
7594
}
7695
}
96+
97+
export class AsyncTestRunner extends TestRunner {
98+
constructor(frame, page, params, suite, test, callback, type) {
99+
super(frame, page, params, suite, test, callback, type);
100+
}
101+
102+
async _runSyncStep(test, page) {
103+
await test.run(page);
104+
}
105+
}
106+
107+
export const TEST_RUNNER_LOOKUP = {
108+
__proto__: null,
109+
default: TestRunner,
110+
async: AsyncTestRunner,
111+
remote: TestRunner,
112+
};

resources/suite-runner.mjs

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { TestRunner } from "./shared/test-runner.mjs";
1+
import { TEST_RUNNER_LOOKUP } from "./shared/test-runner.mjs";
22
import { WarmupSuite } from "./benchmark-runner.mjs";
33

44
export class SuiteRunner {
@@ -75,7 +75,9 @@ export class SuiteRunner {
7575
if (this.#client?.willRunTest)
7676
await this.#client.willRunTest(this.#suite, test);
7777

78-
const testRunner = new TestRunner(this.#frame, this.#page, this.#params, this.#suite, test, this._recordTestResults);
78+
const testRunnerType = this.#suite.type ?? this.params.useAsyncSteps ? "async" : "default";
79+
const testRunnerClass = TEST_RUNNER_LOOKUP[testRunnerType];
80+
const testRunner = new testRunnerClass(this.#frame, this.#page, this.#params, this.#suite, test, this._recordTestResults, testRunnerType);
7981
await testRunner.runTest();
8082
}
8183
performance.mark(suiteEndLabel);
@@ -214,5 +216,6 @@ export class RemoteSuiteRunner extends SuiteRunner {
214216
export const SUITE_RUNNER_LOOKUP = {
215217
__proto__: null,
216218
default: SuiteRunner,
219+
async: SuiteRunner,
217220
remote: RemoteSuiteRunner,
218221
};

0 commit comments

Comments
 (0)