Skip to content
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

Async Runner with Message Channel #458

Merged

Conversation

flashdesignory
Copy link
Contributor

@flashdesignory flashdesignory commented Nov 20, 2024

As discussed in our sync, here is a combination of the AsyncRunner and Message Channel pr.

Relevant code snippet (udpated):

class AsyncRAFTestInvoker extends BaseRAFTestInvoker {
    static mc = new MessageChannel();
    _scheduleCallbacks(resolve) {
        let gotTimer = false;
        let gotMessage = false;
        let gotPromise = false;

        const tryTriggerAsyncCallback = () => {
            if (!gotTimer || !gotMessage || !gotPromise)
                return;

            this._asyncCallback();
            setTimeout(async () => {
                await this._reportCallback();
                resolve();
            }, 0);
        };

        requestAnimationFrame(async () => {
            await this._syncCallback();
            gotPromise = true;
            tryTriggerAsyncCallback();
        });

        requestAnimationFrame(() => {
            setTimeout(() => {
                gotTimer = true;
                tryTriggerAsyncCallback();
            });

            AsyncRAFTestInvoker.mc.port1.addEventListener(
                "message",
                function () {
                    gotMessage = true;
                    tryTriggerAsyncCallback();
                },
                { once: true }
            );
            AsyncRAFTestInvoker.mc.port1.start();
            AsyncRAFTestInvoker.mc.port2.postMessage("speedometer");
        });
    }
}

For testing purposes I kept an explicit type of "async" in the test file, but I opted all default suites into using it.

Initial testing shows that it should also fix the react specific issue.

Other issue solved by this pr: #83

@flashdesignory flashdesignory marked this pull request as ready for review November 21, 2024 02:15
resources/tests.mjs Outdated Show resolved Hide resolved
resources/tests.mjs Outdated Show resolved Hide resolved
@flashdesignory flashdesignory force-pushed the feature/async-runner-message-channel branch from fd6dd12 to 110c94a Compare December 20, 2024 18:38
@flashdesignory
Copy link
Contributor Author

@rniwa - I believe we addressed all the comments. Anything else missing that I can help with?

resources/shared/params.mjs Outdated Show resolved Hide resolved
resources/tests.mjs Outdated Show resolved Hide resolved
export const TEST_INVOKER_LOOKUP = {
__proto__: null,
raf: RAFTestInvoker,
};

export const ASYNC_TEST_INVOKER_LOOKUP = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we really need a separate lookup table? Now that timer-based measurement is gone,
why don't we just have a single lookup table with "raf" and "async" as measurement methods.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cleaned up!

@@ -41,7 +52,7 @@ export class TestRunner {
}
performance.mark(syncStartLabel);
const syncStartTime = performance.now();
this.#test.run(this.#page);
await this._runSyncStep(this.test, this.page);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to have a side effect of always pushing the measurement end until when a promise resolves.
I don't think we want to do that for rAF based measurement method (since that can affect the score)
so maybe we should check the return value of this function and await conditionally?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More concretely, the following code logs: 1, 2, 3:

(async function() { console.log(1); await (() => { })(); console.log(3); })(); console.log(2);

whereas the following code logs 1, 3, 2:

(async function() { console.log(1); (() => { })(); console.log(3); })(); console.log(2);

i.e. await will always delay the execution of the continuation until the end of the current micro-task. While that's highly desirable for async measurement, I don't think we want to affect rAF measurement.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I made it a bit simpler and just passing along a type that we can check to see if we need to await or not

@flashdesignory
Copy link
Contributor Author

cleaned up some stuff from the developer menu integration. Previously i only checked if the suite.type is "async", which always returned false, since we removed the async type from all tests.

Now I am checking both: suite.type === "async" or "params.useAsyncSteps"

Copy link
Member

@rniwa rniwa left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great. Thank you for addressing all the review comments!

@flashdesignory flashdesignory merged commit d979723 into WebKit:main Jan 15, 2025
4 checks passed
@flashdesignory flashdesignory deleted the feature/async-runner-message-channel branch January 15, 2025 19:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
major change A change with major implications on benchmark results or affect governance policy
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants