Skip to content

Add ModAsyncify* passes#2404

Merged
kripken merged 1 commit intomasterfrom
lazy
Oct 23, 2019
Merged

Add ModAsyncify* passes#2404
kripken merged 1 commit intomasterfrom
lazy

Conversation

@kripken
Copy link
Copy Markdown
Member

@kripken kripken commented Oct 23, 2019

These passes are meant to be run after Asyncify has been run, they modify the output. We can assume that we will always unwind if we reach an import, or that we will never unwind, etc.

This is meant to help with lazy code loading, that is, the ability for an initially-downloaded wasm to not contain all the code, and if code not present there is called, we download all the rest and continue with that. That could work something like this:

  • The wasm is created. It contains calls to a special import for lazy code loading.
  • Asyncify is run on it.
  • The initially downloaded wasm is created by running --mod-asyncify-always-and-only-unwind: if the special import for lazy code loading is called, we will definitely unwind, and we won't rewind in this binary.
  • The lazily downloaded wasm is created by running --mod-asyncify-never-unwind: we will rewind into this binary, but no longer need support for unwinding.
    (Optionally, there could also be a third wasm, which has not had Asyncify run on it, and which we'd swap to for max speed.)
  • These --mod-asyncify passes allow the optimizer to do a lot of work, especially for the initially downloaded wasm if we have lots of calls to the lazy code loading import. In that case the optimizer will see that those calls unwind, which means the code after them is not reached, potentially making lots of code dead and removable.

This requires some runtime code to load the second wasm etc., which for Emscripten I'll implement in a PR there, but in principle this could be used in other runtimes too, just like Asyncify itself.

This replaces #2348 , but renames PostAsyncify to ModAsyncify.

@kripken kripken merged commit bb41564 into master Oct 23, 2019
@kripken kripken deleted the lazy branch October 23, 2019 22:09
kripken added a commit to emscripten-core/emscripten that referenced this pull request Oct 25, 2019
This adds emscripten_lazy_load_code(), a function that when called will block
(using Asyncify) and load the complete program. This lets the initial download
not contain code that can be proven to be used only after those calls.

How this works is we emit the initial downloaded wasm after modifying it with
Binaryen to assume that those calls will not rewind, as we only unwind using
that binary (the optimizer can then remove a lot of code). We also emit the
later downloaded wasm, optimized the other way, to assume we only rewind but
never unwind. These transforms are done using ModAsyncify passes from Binaryen
WebAssembly/binaryen#2404

A new option ASYNCIFY_LAZY_LOAD_CODE is necessary to use this (as well as
ASYNCIFY itself).

The test shows an example where the initial download is less than half the size
of the later download. Note that in this model we do download some code twice
(the later download contains the code in the initial one), and we do add some
code size due to Asyncify support. So this will not be an obvious win for every
codebase. But if the later download contains unlikely code that may never be
used, and there is a lot of such code, and we can ignore indirect calls for
Asyncify's purposes, then the win can be significant.
belraquib pushed a commit to belraquib/emscripten that referenced this pull request Dec 23, 2020
This adds emscripten_lazy_load_code(), a function that when called will block
(using Asyncify) and load the complete program. This lets the initial download
not contain code that can be proven to be used only after those calls.

How this works is we emit the initial downloaded wasm after modifying it with
Binaryen to assume that those calls will not rewind, as we only unwind using
that binary (the optimizer can then remove a lot of code). We also emit the
later downloaded wasm, optimized the other way, to assume we only rewind but
never unwind. These transforms are done using ModAsyncify passes from Binaryen
WebAssembly/binaryen#2404

A new option ASYNCIFY_LAZY_LOAD_CODE is necessary to use this (as well as
ASYNCIFY itself).

The test shows an example where the initial download is less than half the size
of the later download. Note that in this model we do download some code twice
(the later download contains the code in the initial one), and we do add some
code size due to Asyncify support. So this will not be an obvious win for every
codebase. But if the later download contains unlikely code that may never be
used, and there is a lot of such code, and we can ignore indirect calls for
Asyncify's purposes, then the win can be significant.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants