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

JS and wasm shrinking (testcase #1) #5836

Closed
kripken opened this issue Nov 22, 2017 · 5 comments
Closed

JS and wasm shrinking (testcase #1) #5836

kripken opened this issue Nov 22, 2017 · 5 comments

Comments

@kripken
Copy link
Member

kripken commented Nov 22, 2017

This issue tracks part of our shrinking initiative, which is Option 1 from #5794. The goal is to shrink the JS and wasm we emit by default. See details in that previous discussion.

To get things started, I looked at one testcase - we should look at more, hence the testcase #1 in the title, this is just to get started. The testcase is a "pure computation" library,

#include <emscripten.h>

EMSCRIPTEN_KEEPALIVE
int add(int x, int y) {
  return x + y;
}

and I built it with -Os --closure 1 -g1 -s WASM=1, then counted lines in the JS. Starting point: 10K of wasm and 24K of JS when fully minified, or when built as I did with -g1 for convenience, it is 32K, in 1,143 lines. In more detail:

Also

If you want to work on one of these, open an issue or a PR, and we can add a link from here.

@curiousdannii
Copy link
Contributor

I like this idea, and I might try to submit a PR for one or two.

I do think changes of this nature warrant a bump to version 1.38.0 if not 2.0.0. With no release descriptions or a dedicated news blog it will be important to signal that these changes are arriving.

Would it help to have a staging branch for them to be merged into before they all get merged into incoming?

@kripken
Copy link
Member Author

kripken commented Nov 25, 2017

We can mention this on the mailing list to get more attention, good idea. We can also try to have more tagged versions around them (helps bisection etc.), but that's being held up by problems on the bots that we just need more help with keeping green (so not sure if that will change).

Otherwise though I think that these changes shouldn't be that dangerous - at least the 3 PRs open so far are not - because they will give very clear error messages when assertions are on (and also in -O0 mode where assertions are on by default). Any breakage people encounter should be brief.

Any change that is more dangerous than that should be handled even more carefully, but hopefully we won't run into such a thing.

@kripken
Copy link
Member Author

kripken commented Nov 28, 2017

Mentioned on the mailing list: https://groups.google.com/forum/#!topic/emscripten-discuss/OY_6JCIjimc

kripken added a commit that referenced this issue Dec 6, 2017
More for #5836 (JS shrinking).

This removes almost all default function exports from the runtime. In ASSERTIONS builds, a warning will be shown if they are used, using the mechanism we introduced for getValue/setValue (which we recently removed from being exported by default).

This reduces the size of the #5836 testcase by almost 20% (!), shrinking us from 21.75 k to 17.65 k.

There are still a few things exported by default, like filesystem support (the file packager emits code that uses those, we should make extra sure this is not confusing for people) and things that aren't functions (need to investigate a good mechanism for warning if they are used incorrectly in ASSERTIONS mode, perhaps a getter on the Module object).

This PR also includes

 * Changelog update explaining the change.
 * Docs improvements.
 * An example in the SDL port of how to export runtime stuff if the port needs it (so e.g. people using SDL don't need to manually add exports, the port can do it for them).
@kripken
Copy link
Member Author

kripken commented Dec 8, 2017

#5919 (meta-DCE, DCE across js+wasm) helps very significantly on this, shrinking the .js by 5% and the .wasm by 84%.

kripken added a commit that referenced this issue Dec 15, 2017
This starts to use binaryen's wasm-metadce tool in -O3, -Os and -Oz, which lets us remove unused code along the boundary of wasm and JS. That is, it can remove things which doing DCE separately on each can't, like cycles between the two worlds.

For example, if wasm imported a JS function, then if the wasm optimizer manages to remove all uses of it, this lets us remove it not just from wasm but also from the JS side too. And the same works the other way as well.

So far, in -Os this shrinks hello world's .js by 3% and .wasm by 18%. This is less effective on large programs, since the removable runtime overhead is smaller - e.g. when using C++ iostreams, it shrinks by 7% / 1%. But where this really shines is on small programs like the testcase in #5836, that just do a little pure computation and don't need a runtime at all: this shrinks that .js by 5% and the .wasm by 84% (mostly thanks to getting rid of malloc/free!). The absolute numbers are interesting for the wasm, it goes from 10,729 bytes to just 1,740, which is getting us most of the way to emitting a really minimal wasm for such inputs. This reason this doesn't get us all the way is because:

 * We need to represent JS's full graph of reachability for wasm-dce to be maximally effective. Currently this just represents imports and exports by parsing them directly. So interesting cycles on the JS side can't be collected yet.
 * We still export a lot of things by default, which prevents this dead code elimination from eliminating them. So as we improve that (#5836 etc.) this will get more powerful.

On the other hand, this does increase compile times noticeably, mostly on tiny files: 47% for hello world and 23% for C++ iostreams. That's why I think this makes sense to do in -Os and -Oz, which care about size, and -O3 is a mode that isn't concerned with compile times.
@kripken
Copy link
Member Author

kripken commented Jan 16, 2018

This testcase is basically done - we emit a tiny 42 byte wasm for it (compared to 10,837 bytes before), the best possible. I'm preparing a blogpost about the progress.

The work here has also helped other testcases as well, we should focus on them next.

@kripken kripken closed this as completed Jan 16, 2018
@kripken kripken changed the title JS Shrinking (testcase #1) JS and wasm Shrinking (testcase #1) Jan 16, 2018
@kripken kripken changed the title JS and wasm Shrinking (testcase #1) JS and wasm shrinking (testcase #1) Jan 16, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants