Prefer using the --separate-asm linker flag to save memory!

121 views
Skip to first unread message

juj j

unread,
May 5, 2016, 3:45:33 AM5/5/16
to emscripte...@googlegroups.com
Hi all,

I'd like to raise some awareness about the awesome --separate-asm linker flag that Alon added some time ago to Emscripten, in version 1.34.8 (9/9/2015). What it does is it splits out the generated output files so that instead of one large .js file that contains all the code, two files foo.js and foo.asm.js will be emitted. The file foo.js will contain the Emscripten preamble, runtime and all the handwritten JS functions (--js-library code) and the --pre-js and --post-js content, whereas the foo.asm.js will only contain the big asm.js module that it assigns to Module.asm.

This has multiple benefits:
   - Often the single monolithic output is too large to handle in browser debugger and most text editors that do syntax highlighting. Often the debugging activities occur on the bridge layer where the compiled code talks to the browser, so it is the handwritten JS code that is of most interest. Separating these out to two files makes it easier to navigate the code and set breakpoints in browsers to the JS runtime itself.
    - Looking towards WebAssembly, if you intend to later ship both a wasm version and an asm.js version of a single page for backwards compatibility, we'll try to make this easy for you by creating a single .html file that loads .wasm if supported, and if not, it'll fall back to the .asm.js version. This will utilize the --separate-asm path.
    - Just recently, we had a big memory improvement land in Firefox (currently in Nightly branch, looking at Firefox 49 release on 2016-09-13) where we are able to recognize the JS script only containing asm.js content, in which case we handle the script memory of that file much more efficiently. JavaScript has from an Emscripten developer's viewpoint a rather exotic feature that requires browsers to retain the JS file contents around, e.g. because one can print the function bodies to a string. For asm.js modules, this is not really needed, so we have pushed this to a cold path by compressing the asm.js script data in memory. This can save 50MB+ of memory on large asm.js codebases. This improvement is something that is asm.js only, WebAssembly will by design avoid this source of memory consumption.
    - Also noteworthy is that when you are building with -s USE_PTHREADS=2 or -s PRECISE_F32=2 flags to enable backwards compatibility for non-SharedArrayBuffer/Math.fround capable browsers, --separate-asm is already implied, because the backwards compatibility architecture on these two features requires this.

For these reasons, we definitely recommend enabling --separate-asm when building if possible. There are some drawbacks to this though, which might make it undesirable for some cases:
   - two files is more than one, which might be inconvenient.
   - there is a small amount of extra complexity that needs to be taken into account when loading. The file foo.asm.js needs to be loaded up before the file foo.js, since the asm.js module needs to be available to run the main file. If you are outputting straight to html with -o foo.html, then Emscripten will generate a proper loader for you, which XHRs the data in in the proper order. If you are outputting -o foo.js however, it will still generate the foo.js and foo.asm.js, but you'll need to manage the required XHR sequence by yourself on your site .html page. If this is not run in correct order, you'll likely see the JS exception "Module['asm'] is not a function" be thrown in the page console.

Hope that is useful!
   Jukka

Brion Vibber

unread,
May 5, 2016, 8:24:12 AM5/5/16
to emscripte...@googlegroups.com
That sounds really useful for debugging!

Hmm, will this work with modular mode? Since it has to reach into Module, but Module is encapsulated in a function and hasn't been instantiated... If the .asm.js file provides a function for the constructor to pass into the module to fill the asm property that ought to work.

-- brion
--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Alon Zakai

unread,
May 5, 2016, 12:09:29 PM5/5/16
to emscripten-discuss
Yeah, I don't think this is compatible with the modularize mode. Separate files means communication between them using global state, so it can't really be fully modular anyhow. We should probably warn or error on this at compile time, if we don't already.

Brion Vibber

unread,
May 5, 2016, 1:05:23 PM5/5/16
to emscripte...@googlegroups.com
On Thursday, May 5, 2016, Alon Zakai <alon...@gmail.com> wrote:
Yeah, I don't think this is compatible with the modularize mode. Separate files means communication between them using global state, so it can't really be fully modular anyhow. We should probably warn or error on this at compile time, if we don't already.

The module constructor function is a global symbol, so it ought to work for the second .js payload to append a function as a property onto it, which the constructor can call with suitable parameters to append the asm property onto the internally created object.

I'll see if I can whip up a patch that works, if it doesn't work I'll whip one up that errors out at compile time. :)

-- brion

Brion Vibber

unread,
May 6, 2016, 1:15:42 PM5/6/16
to emscripte...@googlegroups.com
On Thu, May 5, 2016 at 1:05 PM, Brion Vibber <br...@pobox.com> wrote:
On Thursday, May 5, 2016, Alon Zakai <alon...@gmail.com> wrote:
Yeah, I don't think this is compatible with the modularize mode. Separate files means communication between them using global state, so it can't really be fully modular anyhow. We should probably warn or error on this at compile time, if we don't already.

The module constructor function is a global symbol, so it ought to work for the second .js payload to append a function as a property onto it, which the constructor can call with suitable parameters to append the asm property onto the internally created object.

I'll see if I can whip up a patch that works, if it doesn't work I'll whip one up that errors out at compile time. :)

If that looks feasible I'll clean up the patch, integrate to the frontend, and add tests .

-- brion
Reply all
Reply to author
Forward
0 new messages