Skip to content

Commit 2cf78c5

Browse files
[CP-beta][skwasm] Use queueMicrotask instead of postMessage when single-threaded (flutter#167154)
This pull request is created by [automatic cherry pick workflow](https://github.com/flutter/flutter/blob/main/docs/releases/Flutter-Cherrypick-Process.md#automatically-creates-a-cherry-pick-request) ### Issue Link: flutter#166905 ### Changelog Description: * [flutter/166905](flutter#166905) Fixes a performance regression in skwasm when running in single-threaded mode. ### Impact Description: This fixes a significant regression in the skwasm renderer when running single-thraaded (i.e. in a non-`crossOriginIsolated` browsing context) ### Workaround: Is there a workaround for this issue? The only workaround is to run skwasm in a multi-threaded context or to disable skwasm. ### Risk: What is the risk level of this cherry-pick? - [ x ] Low This essentially returns the single-threaded renderer to the previous message passing strategy. ### Test Coverage: Are you confident that your fix is well-tested by automated tests? - [ x ] Yes ### Validation Steps: What are the steps to validate that this fix works? Built the Wonderous app and take a Chrome profile.
1 parent eeb81b9 commit 2cf78c5

File tree

1 file changed

+60
-39
lines changed

1 file changed

+60
-39
lines changed

engine/src/flutter/lib/web_ui/skwasm/library_skwasm_support.js

Lines changed: 60 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,51 +8,72 @@
88
mergeInto(LibraryManager.library, {
99
$skwasm_support_setup__postset: 'skwasm_support_setup();',
1010
$skwasm_support_setup: function() {
11-
// This value represents the difference between the time origin of the main
12-
// thread and whichever web worker this code is running on. This is so that
13-
// when we report frame timings, that they are in the same time domain
14-
// regardless of whether they are captured on the main thread or the web
15-
// worker.
16-
let timeOriginDelta = 0;
17-
skwasm_registerMessageListener = function(threadId, listener) {
18-
const eventListener = function({data}) {
19-
const skwasmMessage = data.skwasmMessage;
20-
if (!skwasmMessage) {
21-
return;
11+
if (Module["skwasmSingleThreaded"]) {
12+
_skwasm_isSingleThreaded = function() {
13+
return true;
14+
};
15+
16+
let messageListener;
17+
// In single threaded mode, we simply invoke the message listener as a
18+
// microtask, as it's much cheaper than doing a full postMessage
19+
skwasm_registerMessageListener = function(threadId, listener) {
20+
messageListener = listener;
21+
}
22+
skwasm_getCurrentTimestamp = function() {
23+
return performance.now();
24+
};
25+
skwasm_postMessage = function(message, transfers, threadId) {
26+
// If we're in single-threaded mode, we shouldn't use postMessage, as
27+
// it ends up being quite expensive. Instead, just queue a microtask.
28+
queueMicrotask(() => messageListener(message));
29+
};
30+
} else {
31+
_skwasm_isSingleThreaded = function() {
32+
return false;
33+
};
34+
35+
// This value represents the difference between the time origin of the main
36+
// thread and whichever web worker this code is running on. This is so that
37+
// when we report frame timings, that they are in the same time domain
38+
// regardless of whether they are captured on the main thread or the web
39+
// worker.
40+
let timeOriginDelta = 0;
41+
skwasm_registerMessageListener = function(threadId, listener) {
42+
const eventListener = function({data}) {
43+
const skwasmMessage = data.skwasmMessage;
44+
if (!skwasmMessage) {
45+
return;
46+
}
47+
if (skwasmMessage == 'syncTimeOrigin') {
48+
timeOriginDelta = performance.timeOrigin - data.timeOrigin;
49+
return;
50+
}
51+
listener(data);
52+
};
53+
if (!threadId) {
54+
addEventListener("message", eventListener);
55+
} else {
56+
_wasmWorkers[threadId].addEventListener("message", eventListener);
57+
_wasmWorkers[threadId].postMessage({
58+
skwasmMessage: 'syncTimeOrigin',
59+
timeOrigin: performance.timeOrigin,
60+
});
2261
}
23-
if (skwasmMessage == 'syncTimeOrigin') {
24-
timeOriginDelta = performance.timeOrigin - data.timeOrigin;
25-
return;
62+
};
63+
skwasm_getCurrentTimestamp = function() {
64+
return performance.now() + timeOriginDelta;
65+
};
66+
skwasm_postMessage = function(message, transfers, threadId) {
67+
if (threadId) {
68+
_wasmWorkers[threadId].postMessage(message, { transfer: transfers } );
69+
} else {
70+
postMessage(message, { transfer: transfers });
2671
}
27-
listener(data);
2872
};
29-
if (!threadId) {
30-
addEventListener("message", eventListener);
31-
} else {
32-
_wasmWorkers[threadId].addEventListener("message", eventListener);
33-
_wasmWorkers[threadId].postMessage({
34-
skwasmMessage: 'syncTimeOrigin',
35-
timeOrigin: performance.timeOrigin,
36-
});
37-
}
38-
};
39-
skwasm_getCurrentTimestamp = function() {
40-
return performance.now() + timeOriginDelta;
41-
};
42-
skwasm_postMessage = function(message, transfers, threadId) {
43-
if (threadId) {
44-
_wasmWorkers[threadId].postMessage(message, transfers);
45-
} else {
46-
postMessage(message, transfers);
47-
}
48-
};
73+
}
4974

5075
const handleToCanvasMap = new Map();
5176
const associatedObjectsMap = new Map();
52-
53-
_skwasm_isSingleThreaded = function() {
54-
return Module["skwasmSingleThreaded"];
55-
};
5677
_skwasm_setAssociatedObjectOnThread = function(threadId, pointer, object) {
5778
skwasm_postMessage({
5879
skwasmMessage: 'setAssociatedObject',

0 commit comments

Comments
 (0)