Skip to content
kripken edited this page Nov 6, 2011 · 33 revisions

Optimizing the Generated Code

By default Emscripten will compile code in a fairly safe way, and without all the possible optimizations. You should generally try this first, to see if things work properly (if not, see the Debugging page). Afterwards, you may want to compile your code so it runs faster. This page gives some tips on how to do that.

Pre-Emscripten Optimization

You can optimize the .ll file that Emscripten receives by running optimizations in the compiler that generates the .ll file (clang or llvm-gcc). Or you can run llvm-opt on an LLVM bitcode file. Note that -O3 optimization will generate faster code, but significantly bigger - which can be an issue on the web.

Important: Note that emmaken.py will discard optimization parameters. emmaken's job is just to generate .bc. You can then run llvm-opt on the bitcode file yourself, or pass --optimize to emscripten.py which will run LLVM optimizations. (We should rename that flag...)

An additional optimization you can run before Emscripten is the dead function elimination tool, that is in tools/dead_function_eliminator.py in Emscripten. This tool will scrub an .ll file and remove all functions that cannot be run, leaving only those functions that can be reached (through some chain of calls) from main() or from a global constant. This is useful in reducing the size of the .ll file, which both leads to smaller code and faster compilation, but make sure it doesn't remove functions that you want left in (if you are compiling a library, for example).

Decrease Emscripten Runtime Corrections

CORRECT_SIGNS, CORRECT_OVERFLOWS and CORRECT_ROUNDINGS are needed in some code. They add a lot of runtime overhead though. If you can, disable them entirely by editing src/settings.js, and recompiling your code for them to take effect.

If you can't, try to enable them just for the lines they are needed, by setting the CORRECT_* option to 2 (see the linespecific test for more). Use the CHECK_* options with AUTO_OPTIMIZE to find the relevant lines - you should compile with -g to see the original source file and line numbers in the generated JavaScript. As you add more lines to be corrected, the check will no longer warn about them, so you can recompile and run, finding a single line each time.

Note that you don't necessarily need to recompile each time. You can edit the generated source. unSign, for example, takes as a third parameter whether to ignore problems, so changing that to true will ignore signing on that line.

Emscripten Optimizations

The following settings are very important for fast code:

  • OPTIMIZE: This will use native JavaScript variables and other enhancements.
  • RELOOP: This will generate native JavaScript code flow structures (ifs, loops, etc.), instead of emulating code flow using the switch-in-a-loop pattern. Note that currently using this setting will make the compiler very slow.

Other settings:

  • USE_TYPED_ARRAYS: Typed arrays in JavaScript can be much faster than untyped arrays. However this does not always lead to faster code, so you should check if it does or not.
  • FAST_MEMORY: This is the amount of memory that is set to 0 at startup. This tells the JS engine that HEAP should be implemented as a flat fast array, otherwise it may implement HEAP as a hashtable which is extremely slow. This appears to be a problem mainly with V8. Try increasing the value of FAST_MEMORY if you suspect this is the problem. You can also try USE_TYPED_ARRAYS since they are always flat arrays, however you must then also make sure that TOTAL_MEMORY is correct.

Advanced settings:

  • QUANTUM_SIZE of 1 can speed up your code, but is dangerous. See Memory Compression. The default is 4, which is the 'normal', safe value.

Post-Emscripten Optimization

For additional speed, JavaScript optimizers can be run after Emscripten. The best is probably the Closure Compiler, which both minifies and optimizes the code. The YUI Compressor is also useful (tends to optimize less, but runs faster).

Clone this wiki locally