-
Notifications
You must be signed in to change notification settings - Fork 73
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: base async step implementation #420
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,6 +7,13 @@ export class BenchmarkTestStep { | |
constructor(testName, testFunction) { | ||
this.name = testName; | ||
this.run = testFunction; | ||
this.isAsync = false; | ||
} | ||
} | ||
export class AsyncBenchmarkTestStep extends BenchmarkTestStep { | ||
constructor(testName, testFunction) { | ||
super(testName, testFunction); | ||
this.isAsync = true; | ||
} | ||
} | ||
|
||
|
@@ -287,7 +294,24 @@ class TimerTestInvoker extends TestInvoker { | |
} | ||
} | ||
|
||
class RAFTestInvoker extends TestInvoker { | ||
class AsyncTimerTestInvoker extends TestInvoker { | ||
start() { | ||
return new Promise((resolve) => { | ||
setTimeout(async () => { | ||
await this._syncCallback(); | ||
setTimeout(() => { | ||
this._asyncCallback(); | ||
requestAnimationFrame(async () => { | ||
await this._reportCallback(); | ||
resolve(); | ||
}); | ||
}, 0); | ||
}, params.waitBeforeSync); | ||
}); | ||
} | ||
} | ||
|
||
class BaseRAFTestInvoker extends TestInvoker { | ||
start() { | ||
return new Promise((resolve) => { | ||
if (params.waitBeforeSync) | ||
|
@@ -296,7 +320,9 @@ class RAFTestInvoker extends TestInvoker { | |
this._scheduleCallbacks(resolve); | ||
}); | ||
} | ||
} | ||
|
||
class RAFTestInvoker extends BaseRAFTestInvoker { | ||
_scheduleCallbacks(resolve) { | ||
requestAnimationFrame(() => this._syncCallback()); | ||
requestAnimationFrame(() => { | ||
|
@@ -311,6 +337,23 @@ class RAFTestInvoker extends TestInvoker { | |
} | ||
} | ||
|
||
class AsyncRAFTestInvoker extends BaseRAFTestInvoker { | ||
_scheduleCallbacks(resolve) { | ||
requestAnimationFrame(async () => { | ||
await this._syncCallback(); | ||
requestAnimationFrame(() => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This rAF is possibly a bit problematic. It is likely that after resolving syncCallback, one may need to wait quite a while before getting vsync, at least if the callback was very fast. Or, what if we run this._asyncCallback(); using queueMicrotask. That way promise callbacks triggered by _syncCallback() would get run before asyncCallback, but possible setTimeout(0)s wouldn't be. |
||
setTimeout(() => { | ||
this._asyncCallback(); | ||
setTimeout(async () => { | ||
await this._reportCallback(); | ||
resolve(); | ||
}, 0); | ||
}, 0); | ||
}); | ||
}); | ||
} | ||
} | ||
|
||
// https://stackoverflow.com/a/47593316 | ||
function seededHashRandomNumberGenerator(a) { | ||
return function () { | ||
|
@@ -466,26 +509,53 @@ export class BenchmarkRunner { | |
let syncTime; | ||
let asyncStartTime; | ||
let asyncTime; | ||
const runSync = () => { | ||
if (params.warmupBeforeSync) { | ||
performance.mark("warmup-start"); | ||
const startTime = performance.now(); | ||
// Infinite loop for the specified ms. | ||
while (performance.now() - startTime < params.warmupBeforeSync) | ||
continue; | ||
performance.mark("warmup-end"); | ||
let runSync; | ||
let invokerClass; | ||
if (!test.isAsync) { | ||
invokerClass = params.measurementMethod === "raf" ? RAFTestInvoker : TimerTestInvoker; | ||
runSync = () => { | ||
if (params.warmupBeforeSync) { | ||
performance.mark("warmup-start"); | ||
const startTime = performance.now(); | ||
// Infinite loop for the specified ms. | ||
while (performance.now() - startTime < params.warmupBeforeSync) | ||
continue; | ||
performance.mark("warmup-end"); | ||
} | ||
performance.mark(startLabel); | ||
const syncStartTime = performance.now(); | ||
test.run(this._page); | ||
const syncEndTime = performance.now(); | ||
performance.mark(syncEndLabel); | ||
|
||
syncTime = syncEndTime - syncStartTime; | ||
|
||
performance.mark(asyncStartLabel); | ||
asyncStartTime = performance.now(); | ||
} | ||
performance.mark(startLabel); | ||
const syncStartTime = performance.now(); | ||
test.run(this._page); | ||
const syncEndTime = performance.now(); | ||
performance.mark(syncEndLabel); | ||
|
||
syncTime = syncEndTime - syncStartTime; | ||
|
||
performance.mark(asyncStartLabel); | ||
asyncStartTime = performance.now(); | ||
}; | ||
} else { | ||
invokerClass = params.measurementMethod === "raf" ? AsyncRAFTestInvoker : AsyncTimerTestInvoker; | ||
runSync = async () => { | ||
if (params.warmupBeforeSync) { | ||
performance.mark("warmup-start"); | ||
const startTime = performance.now(); | ||
// Infinite loop for the specified ms. | ||
while (performance.now() - startTime < params.warmupBeforeSync) | ||
continue; | ||
performance.mark("warmup-end"); | ||
} | ||
performance.mark(startLabel); | ||
const syncStartTime = performance.now(); | ||
await test.run(this._page); | ||
const syncEndTime = performance.now(); | ||
performance.mark(syncEndLabel); | ||
|
||
syncTime = syncEndTime - syncStartTime; | ||
|
||
performance.mark(asyncStartLabel); | ||
asyncStartTime = performance.now(); | ||
}; | ||
} | ||
const measureAsync = () => { | ||
// Some browsers don't immediately update the layout for paint. | ||
// Force the layout here to ensure we're measuring the layout time. | ||
|
@@ -500,7 +570,6 @@ export class BenchmarkRunner { | |
performance.measure(`${suite.name}.${test.name}-async`, asyncStartLabel, asyncEndLabel); | ||
}; | ||
const report = () => this._recordTestResults(suite, test, syncTime, asyncTime); | ||
const invokerClass = params.measurementMethod === "raf" ? RAFTestInvoker : TimerTestInvoker; | ||
const invoker = new invokerClass(runSync, measureAsync, report); | ||
|
||
return invoker.start(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
import { BenchmarkTestStep } from "./benchmark-runner.mjs"; | ||
import { BenchmarkTestStep, AsyncBenchmarkTestStep } from "./benchmark-runner.mjs"; | ||
import { todos } from "./translations.mjs"; | ||
|
||
const numberOfItemsToAdd = 100; | ||
|
@@ -953,7 +953,27 @@ Suites.push({ | |
page.querySelector("#add-scatter-chart-button").click(); | ||
}), | ||
], | ||
}); | ||
}) | ||
|
||
Suites.push({ | ||
name: "Charts-chartjs-Async", | ||
url: "charts/dist/chartjs.html", | ||
tags: ["chart"], | ||
async prepare(page) {}, | ||
tests: [ | ||
new AsyncBenchmarkTestStep("Draw scatter", (page) => { | ||
page.querySelector("#prepare").click(); | ||
page.querySelector("#add-scatter-chart-button").click(); | ||
}), | ||
new AsyncBenchmarkTestStep("Show tooltip", (page) => { | ||
page.querySelector("#open-tooltip").click(); | ||
}), | ||
new AsyncBenchmarkTestStep("Draw opaque scatter", (page) => { | ||
page.querySelector("#opaque-color").click(); | ||
page.querySelector("#add-scatter-chart-button").click(); | ||
}), | ||
], | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, what is async here? Should the test functions be async? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah this should be |
||
});; | ||
|
||
Suites.push({ | ||
name: "React-Stockcharts-SVG", | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, so this makes sync callback the async thingie. Which makes sense given how callbacks are used currently, but naming is a bit confusing then. Perhaps we could rename the callbacks to not be sync and async, but something else. Not sure what.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah absolutely, this is more confusing than ever :).
main
vs .trailing
or so?blocking
vs.delayed
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about something like this?