Merge pull request #2802 from hamishwillee/incoming
Fixes to debugging topic (and related changes)
This commit is contained in:
Коммит
c3f61e470e
|
@ -992,7 +992,9 @@ Typedefs
|
|||
emscripten_align2_double
|
||||
emscripten_align1_double
|
||||
|
||||
Unaligned types. These may be used to force LLVM to emit unaligned loads/stores in places in your code where ``SAFE_HEAP`` found an unaligned operation.
|
||||
Unaligned types. These may be used to force LLVM to emit unaligned loads/stores in places in your code where :ref:`SAFE_HEAP <debugging-SAFE-HEAP>` found an unaligned operation.
|
||||
|
||||
For usage examples see `tests/core/test_set_align.c <https://github.com/kripken/emscripten/blob/master/tests/core/test_set_align.c>`_.
|
||||
|
||||
.. note:: It is better to avoid unaligned operations, but if you are reading from a packed stream of bytes or such, these types may be useful!
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ This section lists Emscripten's public API, organised by header file. At a very
|
|||
Embind API for binding C++ functions and classes so that they can be called from JavaScript in a natural way.
|
||||
|
||||
- :ref:`trace-h`:
|
||||
A tracing API for doing memory usage analysis.
|
||||
A tracing API for doing memory usage analysis.
|
||||
|
||||
- :ref:`api-reference-advanced-apis`:
|
||||
APIs for advanced users/core developers.
|
||||
|
|
|
@ -269,7 +269,7 @@ Another possible cause of this error is the lack of ``make``, which is necessary
|
|||
Why does running LLVM bitcode generated by emcc through **lli** break with errors about ``impure_ptr``?
|
||||
=======================================================================================================
|
||||
|
||||
.. note:: `lli <http://llvm.org/releases/3.0/docs/CommandGuide/html/lli.html>`_ is not maintained, and has odd errors and crashes. We do include **tools/nativize_llvm.py** (which compiles bitcode to a native executable) but it will also hit the ``impure_ptr`` error.
|
||||
.. note:: :term:`lli` is not maintained, and has odd errors and crashes. We do include **tools/nativize_llvm.py** (which compiles bitcode to a native executable) but it will also hit the ``impure_ptr`` error.
|
||||
|
||||
The issue is that *newlib* uses ``impure_ptr`` code, while *glibc* uses something else. The result is that bitcode built with the Emscripten will not run locally unless your machine uses *newlib* (basically, only embedded systems).
|
||||
|
||||
|
|
|
@ -1,135 +1,181 @@
|
|||
.. _Optimizing-Code:
|
||||
|
||||
====================================
|
||||
Optimizing Code (under-construction)
|
||||
Optimizing Code (ready-for-review)
|
||||
====================================
|
||||
|
||||
By default Emscripten will compile code in a fairly safe way, and without all the possible optimizations. You should generally try this first, to make sure things work properly (if not, see the :ref:`Debugging` page). Afterwards, you may want to compile your code so it runs faster. This page explains how.
|
||||
|
||||
.. note:: You can also optimize the source code you are compiling into JavaScript, see :ref:`Optimizing-the-source-code`.
|
||||
|
||||
Using emcc
|
||||
==========
|
||||
|
||||
The recommended way to optimize code is with :ref:`emcc <emccdoc>`. *Emcc* works like *gcc*, and basic usage is presented in the Emscripten :ref:`Tutorial`. As mentioned there, you can use *emcc* to optimize, for example
|
||||
|
||||
::
|
||||
|
||||
emcc -O2 file.cpp
|
||||
|
||||
To see what the different optimizations levels do, run
|
||||
|
||||
::
|
||||
|
||||
emcc --help
|
||||
|
||||
- The meaning of ``-O1, -O2`` etc. in *emcc* are not identical to gcc/clang/other compilers, even though they have been chosen to be as familiar. They can't be, because optimizing JavaScript is very different than optimizing native code. See the ``--help`` as mentioned before for details.
|
||||
- If you compile several files into a single JavaScript output, be sure to specify the same optimization flags during all invocations of *emcc* - both when compiling sources into objects, and objects into JavaScript or HTML. See :ref:`Building-Projects` for more details.
|
||||
- Aside from ``-Ox`` options, there are ``--llvm-lto`` options that you can read about in ``emcc --help``.
|
||||
Generally you should first compile and run your code without optimizations (the default). Once you are sure that the code runs correctly, you can use the techniques in this article to make it load and run faster.
|
||||
|
||||
How to optimize code
|
||||
====================
|
||||
|
||||
The following procedure is how you should normally optimize your code. Note that all the flags here are for the link stage (when compiling bitcode to JavaScript), not to optimizing source files.
|
||||
Code is optimized by specifying :ref:`optimization flags <emcc-compiler-optimization-options>` when running :ref:`emcc <emccdoc>`. The levels include: :ref:`O0 <emcc-O0>` (no optimization), :ref:`O1 <emcc-O1>`, :ref:`O2 <emcc-O2>`, :ref:`Os <emcc-Os>`, :ref:`Oz <emcc-Oz>`, and :ref:`O3 <emcc-O3>`.
|
||||
|
||||
For example, to compile with optimization level ``-O2``:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
emcc -O2 file.cpp
|
||||
|
||||
The higher optimization levels introduce progressively more aggressive optimization, resulting in improved performance and code size at the cost of increased compilation time. The levels can also highlight different issues related to undefined behavior in code.
|
||||
|
||||
The optimization level you should use depends mostly on the current stage of development:
|
||||
|
||||
- When first porting code, run *emcc* on your code using the default settings (without optimization). Check that your code works and :ref:`debug <Debugging>` and fix any issues before continuing.
|
||||
- Build with lower optimization levels during development for a shorter compile/test iteration cycle (``-O0`` or ``-O1``).
|
||||
- Build with ``-O2`` when releasing your code — this is a highly optimized but still safe build. ``-O3`` provides an even more optimized build, but as it includes newer optimizations, must be more thoroughly tested.
|
||||
- Other optimizations are discussed in the following sections.
|
||||
|
||||
In addition to the ``-Ox`` options, there are separate compiler options that can be used to control the JavaScript optimizer (:ref:`js-opts <emcc-js-opts>`), LLVM optimizations (:ref:`llvm-opts <emcc-llvm-opts>`) and LLVM link-time optimizations (:ref:`llvm-lto <emcc-llvm-lto>`).
|
||||
|
||||
.. note::
|
||||
|
||||
- The meanings of the *emcc* optimization flags (``-O1, -O2`` etc.) are different to the similarly-named options in *gcc*, *clang*, and other compilers, because optimizing JavaScript is very different to optimizing native code. The mapping of the *emcc* levels to the the LLVM bitcode optimization levels is documented in the reference.
|
||||
- If you compile several files into a single JavaScript output, be sure to specify the **same** optimization flags when compiling sources into objects, and objects into JavaScript or HTML. See :ref:`Building-Projects` for more details.
|
||||
|
||||
- First, run emcc on your code without optimization. The default settings are set to be safe. Check that your code works (if not, see the :ref:`Debugging` page) before continuing.
|
||||
- Build with ``-O2`` to get an optimized build.
|
||||
- Build with ``-O0`` or ``-O1`` if you want faster iteration times, 0 is the fastest to build but slowest to run, while 1 is in the middle.
|
||||
- If you want an even more optimized build than ``-O2``, see the rest of this page.
|
||||
|
||||
Advanced compiler settings
|
||||
==========================
|
||||
|
||||
There are several flags you can pass to the compiler to affect code generation, many of which can affect performance. Look in ``src/settings.js`` for which options are available and what they mean (and if you want to look under the hood, see ``apply_opt_level`` in ``tools/shared.py`` for how -O1,2,3 affect them), as well as ``emcc --help``. A few useful ones are:
|
||||
There are several flags you can :ref:`pass to the compiler <emcc-s-option-value>` to affect code generation, and which will also affect performance — for example :ref:`DISABLE_EXCEPTION_CATCHING <optimizing-code-exception-catching>`, :term:`RELOOP <relooping>`. These, and others, are documented in `src/settings.js <https://github.com/kripken/emscripten/blob/master/src/settings.js>`_. Some of these will also be directly affected by the optimization settings (you can find out which ones by searching for ``apply_opt_level`` in `tools/shared.py <https://github.com/kripken/emscripten/blob/master/tools/shared.py#L906>`_).
|
||||
|
||||
- ``NO_EXIT_RUNTIME`` - When set, code can run but we never "shut down" the runtime environment, in the sense that no global destructors are run, no atexit calls are executed, etc. This is useful if your ``main()`` function finishes but you still want to execute code, and in fact necessary otherwise if you depend on a global structure it may have gone away - and for that reason, at runtime if we see that you call something like :c:func:`emscripten_set_main_loop` then we will never shut down the runtime. However, if you build with ``-s NO_EXIT_RUNTIME=1`` then we know at **compile** time that you want that, which lets the compiler statically get rid of atexit calls and global destructors, which can improve code size and startup speed.
|
||||
A few useful flags are:
|
||||
|
||||
-
|
||||
.. _optimizing-code-no-exit-runtime:
|
||||
|
||||
``NO_EXIT_RUNTIME``: Building with ``-s NO_EXIT_RUNTIME=1`` lets the compiler know that you don't want to shut down the runtime environment after the ``main()`` function finishes. This allows it to discard the ``atexit`` and global destructor calls it would otherwise make, improving code size and startup speed.
|
||||
|
||||
This is useful if your ``main()`` function finishes but you still want to execute code, for example in an app that uses a :ref:`main loop function <emscripten-runtime-environment-main-loop>`.
|
||||
|
||||
.. note:: Emscripten will not shut down the runtime if it detects :c:func:`emscripten_set_main_loop`, but it is better to optimise away the unnecessary code.
|
||||
|
||||
|
||||
|
||||
Very large projects
|
||||
===================
|
||||
|
||||
Very large projects can hit some issues that smaller ones will never see:
|
||||
This section describes optimisations and issues that are only relevant to very large projects.
|
||||
|
||||
.. _optimizing-code-memory-initialization:
|
||||
|
||||
Memory initialization
|
||||
---------------------
|
||||
|
||||
By default Emscripten emits the static memory initialization inside the **.js** file, for simplicity. If it is very large, it can slow down startup, or even cause issues in JavaScript engines with limits on array sizes (you may see ``Array initializer too large`` or ``Too much recursion`` for example), and it also leads to very large JavaScript files. To avoid that, Emscripten can emit a binary file on the side by running emcc with
|
||||
By default Emscripten emits the static memory initialization code inside the **.js** file. This can cause the JavaScript file to be very large, which will slow down startup. It can also cause problems in JavaScript engines with limits on array sizes, resulting in errors like ``Array initializer too large`` or ``Too much recursion``.
|
||||
|
||||
``--memory-init-file 1``
|
||||
The *emcc* :ref:`memory-init-file 1 <emcc-memory-init-file>` option causes the compiler to emit this code in a separate binary file with suffix **.mem**. The **.mem** file is loaded (asynchronously) by the main **.js** file before ``main()`` is called and compiled code is able to run.
|
||||
|
||||
This is the default in ``-O2`` and above in Emscripten 1.21.1 and above; in earlier versions, you can enable it manually. When utilized, a file with suffix ``.mem`` should appear, and it will be loaded by the JavaScript. See ``emcc --help`` for more details.
|
||||
.. note: From Emscripten 1.21.1 this setting is enabled by default for ``-O2`` builds (and above).
|
||||
|
||||
Optimization levels
|
||||
-------------------
|
||||
|
||||
You might want to build some source files in your project with ``-Os`` or ``-Oz`` to reduce code size, and the rest using ``-O2`` which gives better performance (but increases code size). This allows you to keep files you know are less performance-sensitive at a minimal size, while keeping the files that need to be fast at maximal speed.
|
||||
.. _optimizing-code-oz-os:
|
||||
|
||||
(Note that this only matters during the source to bitcode phase: during bitcode to JavaScript, ``-Os`` and ``-Oz`` are the same as ``-O2`` as there are currently no JavaScript specific optimization flags for ``-Os`` or ``-Oz``.)
|
||||
Trade off code size and performance
|
||||
-------------------------------------
|
||||
You may wish to build the less performance-sensitive files in your project using :ref:`Os <emcc-Os>` or :ref:`Oz <emcc-Oz>` and the remainder using :ref:`O2 <emcc-O2>` (:ref:`Os <emcc-Os>` and :ref:`Oz <emcc-Oz>` are similar to :ref:`O2 <emcc-O2>`, but reduce code size at the expense of performance).
|
||||
|
||||
.. note:: This only matters when compiling the source to bitcode. There are currently no JavaScript specific optimization flags for ``-Os`` or ``-Oz``, and these map to ``-O2`` in the bitcode to JavaScript phase.
|
||||
|
||||
Code size
|
||||
---------
|
||||
|
||||
Tips for reducing code size include:
|
||||
|
||||
- Memory init file as mentioned above.
|
||||
- Using -Os or -Oz, as also mentioned above.
|
||||
- Build bitcode to JavaScript with -O3 which runs the expensive variable reuse pass (registerizeHarder)
|
||||
- Use llvm LTO during bitcode to JavaScript ``-s INLINING_LIMIT=1 --llvm-lto 1`` (can break some code as the LTO code path is less tested)
|
||||
- That command also disables inlining. If sources were built with -Os or -Oz, it will avoid inlining anyhow for the most part, and you can try just ``--llvm-lto 1``
|
||||
- Use closure on the outside non-asm.js code ``--closure 1`` (can break some code)
|
||||
- Define a separate memory initialization file (as :ref:`mentioned above <optimizing-code-memory-initialization>`).
|
||||
- Use ``-Os`` or ``-Oz`` (as :ref:`mentioned above <optimizing-code-oz-os>`).
|
||||
- Build bitcode to JavaScript with :ref:`O3 <emcc-O3>`. This runs the expensive variable reuse pass (``registerizeHarder``). It is slower to compile and uses newer (less tested) optimizations than ``-O2``.
|
||||
- Use :ref:`llvm-lto <emcc-llvm-lto>` when compiling from bitcode to JavaScript: ``--llvm-lto 1``. This can break some code as the LTO code path is less tested.
|
||||
- Disable :ref:`optimizing-code-inlining`: ``-s INLINING_LIMIT=1``. Compiling with -Os or -Oz generally avoids inlining too.
|
||||
- Use :ref:`closure <emcc-closure>` on the outside non-asm.js code: ``--closure 1``. This can break some code.
|
||||
|
||||
.. _optimizing-code-outlining:
|
||||
|
||||
Outlining
|
||||
---------
|
||||
|
||||
``OUTLINING_LIMIT`` breaks up large functions into smaller ones, by "outlining" code. This helps startup speed as well as runtime speed in some cases, particularly when a codebase has huge functions, which confuse JavaScript engines. For more details see `this blog post <http://mozakai.blogspot.com/2013/08/outlining-workaround-for-jits-and-big.html>`_.
|
||||
JavaScript engines will often compile very large functions slowly (relative to their size), and fail to optimize them effectively (or at all). One approach to this problem is to use "outlining", breaking them into smaller functions that can be compiled and optimized more effectively.
|
||||
|
||||
Aggressive Variable Elimination
|
||||
Outlining increases overall code size, and can itself make some code less optimised. Despite this, outlining can sometimes improve both startup and runtime speed. For more information see `this blog post <http://mozakai.blogspot.com/2013/08/outlining-workaround-for-jits-and-big.html>`_.
|
||||
|
||||
The setting ``OUTLINING_LIMIT`` defines the function size at which Emscripten will try to break large functions into smaller ones. Search for this setting in `settings.js <https://github.com/kripken/emscripten/blob/master/src/settings.js>`_ for information on how to determine what functions may need to be outlined and how to choose an appropriate function size.
|
||||
|
||||
|
||||
.. _optimizing-code-aggressive-variable-elimination:
|
||||
|
||||
Aggressive variable elimination
|
||||
-------------------------------
|
||||
|
||||
You can enable aggressive variable elimination with ``-s AGGRESSIVE_VARIABLE_ELIMINATION=1``. This will then attempt to remove variables whenever possible, even at the cost of increasing code size by duplicating expressions. This can improve speed in some cases where you have extremely large functions, for example it can make sqlite 7% faster (which has a huge interpreter loop with thousands of lines in it). However it can also he harmful in some cases, so test before using it.
|
||||
Aggressive variable elimination attempts to remove variables whenever possible, even at the cost of increasing code size by duplicating expressions. This can improve speed in cases where you have extremely large functions. For example it can make sqlite 7% faster (which has a huge interpreter loop with thousands of lines in it).
|
||||
|
||||
You can enable aggressive variable elimination with ``-s AGGRESSIVE_VARIABLE_ELIMINATION=1``.
|
||||
|
||||
.. note:: This setting can be harmful in some cases. Test before using it.
|
||||
|
||||
|
||||
Other optimization issues
|
||||
=========================
|
||||
|
||||
Exception Catching
|
||||
------------------
|
||||
.. _optimizing-code-exception-catching:
|
||||
|
||||
C++ exceptions
|
||||
--------------
|
||||
|
||||
C++ exceptions are turned off by default in ``-O1`` (and above). This prevents the generation of ``try-catch`` blocks, which lets the code run much faster, and also makes the code smaller.
|
||||
|
||||
To re-enable exceptions in optimized code, run *emcc* with ``-s DISABLE_EXCEPTION_CATCHING=0`` (see `src/settings.js <https://github.com/kripken/emscripten/blob/master/src/settings.js>`).
|
||||
|
||||
In ``-O1`` and above exception catching is disabled. This prevents the generation of try-catch blocks, which lets the code run much faster, and also makes the code smaller. To re-enable them, run emcc with ``-s DISABLE_EXCEPTION_CATCHING=0``.
|
||||
|
||||
Viewing code optimization passes
|
||||
--------------------------------
|
||||
|
||||
If you run emcc with ``EMCC_DEBUG=1`` (so, something like ``EMCC_DEBUG=1 emcc``), then it will output all the intermediate steps after each optimization pass. The output will be in ``TEMP_DIR/emscripten_temp``, where ``TEMP_DIR`` is by default ``/tmp`` (and can be modified in ``~/.emscripten``). ``EMCC_DEBUG=2`` will output even more information, a separate file will be saved for each JavaScript optimization pass.
|
||||
Enable :ref:`debugging-EMCC_DEBUG` to output files for each JavaScript optimization pass.
|
||||
|
||||
|
||||
.. _optimizing-code-inlining:
|
||||
|
||||
Inlining
|
||||
--------
|
||||
|
||||
Inlining often generates large functions. These allow the compiler's optimizations to be more effective, but have downsides for JavaScript engines: They often do not try to optimize big functions for fear or long JIT times, or they do JIT them and it causes noticeable pauses. So ironically (or paradoxically) using -O1 or -O2, which inline by default, can actually decrease performance in some cases.
|
||||
Inlining often generates large functions, as these allow the compiler's optimizations to be more effective. Unfortunately large functions can be relatively far slower at runtime because JavaScript engines often do not optimize big functions (for fear of long JIT times), or they do optimize them and it causes noticeable pauses.
|
||||
|
||||
You can try to avoid this issue by disabling inlining (in specific files or everywhere), or by using the outliner feature, see `this blog post <http://mozakai.blogspot.com/2013/08/outlining-workaround-for-jits-and-big.html>`_.
|
||||
.. note:: ``-O1`` and ``-O2`` inline functions by default. Ironically, this can actually decrease performance in some cases!
|
||||
|
||||
You can try to avoid this issue by disabling inlining (in specific files or everywhere), or by using :ref:`optimizing-code-outlining`.
|
||||
|
||||
|
||||
.. _optimizing-code-unsafe-optimisations:
|
||||
|
||||
Unsafe optimizations
|
||||
--------------------
|
||||
====================
|
||||
|
||||
A few **UNSAFE** optimizations you might want to try are:
|
||||
|
||||
- ``-s FORCE_ALIGNED_MEMORY=1``: Makes all memory accesses fully aligned. This can break on code that actually requires unaligned accesses.
|
||||
- ``-s PRECISE_I64_MATH=1``: When disabled, does shortcuts when implementing 64-bit addition etc., using doubles instead of full emulation. This will break on code that uses the full range of 64-bit numbers.
|
||||
- ``--llvm-lto 1``: This enables LLVM's link-time opts, which can help in some cases but there are known issues with them as well, so use at your own risk. (There are btw a few modes aside from ``1``, see ``emcc --help``.)
|
||||
- ``--closure 1``: This can help with reducing the size of the non-generated (support/glue) code, and with startup. However it can break if you do not do proper closure compiler annotations and exports.
|
||||
- ``--llvm-lto 1``: This enables LLVM's link-time optimizations, which can help in some cases. However there are known issues with these optimizations, so code must need to be extensively tested. See :ref:`llvm-lto <emcc-llvm-lto>` for information about the other modes.
|
||||
- ``--closure 1``: This can help with reducing the size of the non-generated (support/glue) code, and with startup. However it can break if you do not do proper :term:`Closure Compiler` annotations and exports.
|
||||
|
||||
.. _optimizing-code-profiling:
|
||||
|
||||
Profiling
|
||||
=========
|
||||
|
||||
Modern browsers have JavaScript profilers, which can help find the slower parts in your code. You should build your project with ``--profiling`` for this, that flag will leave the code in a readable-enough state for profiling purposes (``--profiling`` should be added in addition to your other optimization flags like ``-O1``, ``-O2`` or ``-O3``).
|
||||
Modern browsers have JavaScript profilers that can help find the slower parts in your code. As each browser's profiler has limitations, it is highly recommended to profile in multiple browsers in order to get the best information.
|
||||
|
||||
As each browser's profiler has limitations, it is highly recommended to profile in multiple browsers in order to get the best information. Also, in Firefox it is a good idea to profile both with and without asm.js optimizations enabled (can remove the ``'use asm'`` string to disable).
|
||||
To ensure that compiled code contains enough information for profiling, build your project with :ref:`profiling <emcc-profiling>` as well as optimization and other flags:
|
||||
|
||||
Troubleshooting Slowness
|
||||
========================
|
||||
.. code-block:: bash
|
||||
|
||||
If you get worse performance than you expect - you should get about 1/2 the speed of a native build - then aside from the tips above, here is a list of things to check:
|
||||
emcc -O2 --profiling file.cpp
|
||||
|
||||
- Did you build with -O2 or -O3, **both** when compiling source code files **and** when generating JavaScript? The first is needed for LLVM optimizations, the latter for JavaScript optimizations, all of which are crucial (see :ref:`Building-Projects`).
|
||||
- Is performance ok on one browser, but not in another? Testing on multiple browsers is always good to understand where a bug or performance issue lies. Please file a bug on the browser where things are slow.
|
||||
- In firefox, does the code validate? Look for "Successfully compiled asm.js code in the web console. If instead you see a validation error, make sure you are running an up-to-date version of Firefox, and are building using an up-to-date version of Emscripten. If the problem exists with those, please file a bug on Emscripten.
|
||||
|
||||
Troubleshooting poor performance
|
||||
================================
|
||||
|
||||
Emscripten-compiled code can currently achieve approximately half the speed of a native build. If the performance is significantly poorer than expected then, in addition to the tips above, here is a list of things to check:
|
||||
|
||||
- :ref:`Building-Projects` is a two-stage process: compiling source code files to LLVM **and** generating JavaScript from LLVM. Did you build using the same optimization values in **both** steps (``-O2`` or ``-O3``)?
|
||||
- Test on multiple browsers. If performance is acceptable on one browser and significantly poorer on another, then :ref:`file a bug <bug-reports>` (noting the problem browser).
|
||||
- Does the code *validate* in Firefox (look for "Successfully compiled asm.js code" in the web console). If you see a validation error when using an up-to-date version of Firefox and Emscripten then please file a bug report
|
||||
|
||||
|
|
|
@ -1,139 +1,268 @@
|
|||
.. _Debugging:
|
||||
|
||||
=======================
|
||||
Debugging (wiki-import)
|
||||
============================
|
||||
Debugging (ready-for-review)
|
||||
============================
|
||||
|
||||
One of the main advantages of debugging cross platform Emscripten code is that the same cross-platform source code can be debugged on either the native platform or using the Web browser's increasingly-powerful debugger, profiler and other tools.
|
||||
|
||||
Emscripten provides a lot of functionality and tools to aid debugging:
|
||||
|
||||
- :ref:`Compiler debug information flags <debugging-debug-information-g>` that allow you to preserve debug information in compiled code and even create source maps so that you can step through the native C++ source when debugging in the browser.
|
||||
- :ref:`Debug mode <debugging-EMCC_DEBUG>` emits debug logs and stores intermediate build files for analysis.
|
||||
- :ref:`Compiler settings <debugging-compilation-settings>` that enable runtime checking of memory accesses and common allocation errors.
|
||||
- :ref:`debugging-manual-debugging` of Emscripten-generated code is also supported, and is in some ways even better than on native platforms.
|
||||
- :ref:`debugging-autodebugger` automatically instruments LLVM bitcode to write out each store to memory.
|
||||
|
||||
This article describes the main tools and settings provided by Emscripten for debugging, along with a section explaining how to debug a number of :ref:`debugging-emscripten-specific-issues`.
|
||||
|
||||
|
||||
.. _debugging-debug-information-g:
|
||||
|
||||
Debug information
|
||||
=================
|
||||
|
||||
:ref:`Emcc <emccdoc>` strips out most debug information from :ref:`optimized builds <Optimizing-Code>`. Optimisation level :ref:`-01 <emcc-O1>` and above remove LLVM debug information, and also disable runtime :ref:`ASSERTIONS <debugging-ASSERTIONS>` checks. From optimization level :ref:`-02 <emcc-O2>` the code is minified by the :term:`Closure Compiler` and becomes virtually unreadable.
|
||||
|
||||
The *emcc* :ref:`-g flag <emcc-g>` can be used to preserve debug information in the compiled output. By default, this option preserves white-space, function names and variable names.
|
||||
|
||||
The flag can also be specified with one of five levels: :ref:`-g0 <emcc-g0>`, :ref:`-g1 <emcc-g1>`, :ref:`-g2 <emcc-g2>`, :ref:`-g3 <emcc-g3>`, :ref:`-g4 <emcc-g4>`. Each level builds on the previous level to provide progressively more debug information in the compiled output. The :ref:`-g3 flag <emcc-g3>` provides the same level of debug information as the :ref:`-g flag <emcc-g>`.
|
||||
|
||||
The :ref:`-g4 <emcc-g4>` option provides the most debug information — it generates source maps that allow you to view and debug the *C/C++ source code* in your browser's debugger on Firefox, Chrome or Safari!
|
||||
|
||||
.. note:: Some optimizations may be disabled when used in conjunction with the debug flags. For example, if you compile with ``-O3 -g4`` some of the normal ``-O3`` optimizations will be disabled in order to provide the requested debugging information.
|
||||
|
||||
.. _debugging-EMCC_DEBUG:
|
||||
|
||||
Debug mode (EMCC_DEBUG)
|
||||
=======================
|
||||
|
||||
For a quick overview of debugging Emscripten-generated code, see `these slides <http://people.mozilla.org/~lwagner/gdc-pres/gdc-2014.html#/20>`_.
|
||||
The ``EMCC_DEBUG`` environment variable can be set to enable Emscripten's debug mode:
|
||||
|
||||
.. comment:: Pulled from below, might be useful: If you think you may have hit an Emscripten codegen bug, there are a few tools to help you.
|
||||
.. code-block:: bash
|
||||
|
||||
Limitation or Bug?
|
||||
# Linux or Mac OS X
|
||||
EMCC_DEBUG=1 ./emcc tests/hello_world.cpp -o hello.html
|
||||
|
||||
# Windows
|
||||
set EMCC_DEBUG=1
|
||||
emcc tests/hello_world.cpp -o hello.html
|
||||
set EMCC_DEBUG=0
|
||||
|
||||
With ``EMCC_DEBUG=1`` set, :ref:`emcc <emccdoc>` emits debug output and generates intermediate files for the compiler's various stages. ``EMCC_DEBUG=2`` additionally generates intermediate files for each JavaScript optimizer pass.
|
||||
|
||||
The debug logs and intermediate files are output to **TEMP_DIR/emscripten_temp**, where ``TEMP_DIR`` is by default **/tmp** (it is defined in the :ref:`.emscripten <compiler-configuration-file>`).
|
||||
|
||||
The debug logs can be analysed to profile and review the changes that were made in each step.
|
||||
|
||||
.. note:: The debug mode can also be enabled using by specifying the :ref:`verbose output <debugging-emcc-v>` compiler flag (``emcc -v``).
|
||||
|
||||
|
||||
.. _debugging-compilation-settings:
|
||||
|
||||
Compiler settings
|
||||
==================
|
||||
|
||||
Emscripten can compile almost but not all C/C++ code out there. Some limitations exist, see :ref:`code-portability-guidelines`.
|
||||
Emscripten has a number of compiler settings that can be useful for debugging. These are set using the :ref:`emcc -s <emcc-s-option-value>` option, and will override any optimization flags. For example:
|
||||
|
||||
Aside from these limitations, it's possible you ran into a bug in Emscripten, such as:
|
||||
.. code-block:: bash
|
||||
|
||||
- Missing functionality. For example, a library function which hasn't yet been implemented in Emscripten. Possible solutions here are to implement the function (see ``library.js``) or to compile it from C++.
|
||||
- An actual mistake in Emscripten. Please report it!
|
||||
./emcc -01 -s ASSERTIONS=1 tests/hello_world
|
||||
|
||||
Optimizations
|
||||
=============
|
||||
The most important settings are:
|
||||
|
||||
Try to build without optimizations (no ``-O1`` etc.). If that has an effect, you can try to disable LLVM optimizations specifically using ``--llvm-opts 0``, see ``emcc --help``.
|
||||
|
||||
Build with ``EMCC_DEBUG=1`` to get intermediate files for the compiler's various stages (output to ``/tmp/emscripten_temp``). ``EMCC_DEBUG=2`` will emit more intermediate files (one for each JavaScript optimizer pass).
|
||||
|
||||
Useful Compilation Settings
|
||||
===========================
|
||||
|
||||
As already mentioned, some useful settings appear in `src/settings.js <https://github.com/kripken/emscripten/blob/master/src/settings.js>`_. Change the settings there and then recompile the code to have them take effect. When code isn't running properly, you should compile with ``ASSERTIONS``, and if that doesn't clear things up, then ``SAFE_HEAP``. ``ASSERTIONS`` adds various runtime checks, and ``SAFE_HEAP`` adds even more (slow) memory access checks like dereferencing 0 and memory alignment issues.
|
||||
|
||||
Inspecting the Generated Code
|
||||
=============================
|
||||
|
||||
See the slides linked to before for the ``-g`` options.
|
||||
|
||||
Another thing you might find useful is to not run JavaScript optimizations, to leave inline source code hints. You can try something like
|
||||
|
||||
::
|
||||
|
||||
/emcc -O2 --js-opts 0 -g4 tests/hello_world_loop.cpp
|
||||
|
||||
which applies only LLVM opts, and basic JavaScript opts but not the JavaScript optimizer, which retains debug info, giving
|
||||
|
||||
::
|
||||
|
||||
function _main() {
|
||||
var label = 0;
|
||||
var $puts=_puts(((8)|0)); //@line 4 "tests/hello_world.c"
|
||||
return 1; //@line 5 "tests/hello_world.c"
|
||||
}
|
||||
|
||||
Debug Info
|
||||
==========
|
||||
|
||||
It can be very useful to compile the C/C++ files with ``-g`` flag to get debugging into - Emscripten will add source file and line number to each line in the generated code. Note, however, that attempting to interpret code compiled with ``-g`` using ``lli`` may cause crashes. So you may need to build once without ``-g`` for ``lli``, then build again with ``-g``. Or, use ``tools/exec_llvm.py`` in Emscripten, which will run lli after cleaning out debug info.
|
||||
-
|
||||
.. _debugging-ASSERTIONS:
|
||||
|
||||
The AutoDebugger
|
||||
===========================
|
||||
``ASSERTIONS=1`` is used to enable runtime checks for common memory allocation errors (e.g. writing more memory than was allocated). It also defines how Emscripten should handle errors in program flow. The value can be set to ``ASSERTIONS=2`` in order to run additional tests.
|
||||
|
||||
``ASSERTIONS=1`` is enabled by default. Assertions are turned off for optimized code (:ref:`-01 <emcc-O1>` and above).
|
||||
|
||||
-
|
||||
.. _debugging-SAFE-HEAP:
|
||||
|
||||
``SAFE_HEAP=1`` adds additional memory access checks, and will give clear errors for problems like dereferencing 0 and memory alignment issues. Use ``SAFE_HEAP=2`` in order to check only specific lines listed in ``SAFE_HEAP_LINES``, and use ``SAFE_HEAP=3`` to check all the lines except those specified. This last option is the most common operation.
|
||||
|
||||
You can also set ``SAFE_HEAP_LOG`` to log ``SAFE_HEAP`` operations.
|
||||
|
||||
The 'nuclear option' when debugging is to use the **autodebugger tool**.
|
||||
A number of other useful debug settings are defined in `src/settings.js <https://github.com/kripken/emscripten/blob/master/src/settings.js>`_. For more information, search that file for the keywords "check" and "debug".
|
||||
|
||||
The autodebugger will rewrite the LLVM bitcode so it prints out each store to memory. You can then run the exact same LLVM bitcode in the LLVM interpreter (lli) and JavaScript, and compare the output (``diff`` is useful if the output is large). For how to use the autodebugger tool, see the ``autodebug`` test.
|
||||
|
||||
The autodebugger can potentially find **any** problem in the generated code, so it is strictly more powerful than the ``CHECK_*`` settings and ``SAFE_HEAP``. However, it has some limitations:
|
||||
.. _debugging-emcc-v:
|
||||
|
||||
- The autodebugger generates a lot of output. Using ``diff`` can be very helpful here.
|
||||
- The autodebugger doesn't print out pointer values, just simple numerical values. The reason is that pointer values change from run to run, so you can't compare them. However, on the one hand this may miss potential problems, and on the other, a pointer may be converted into an integer and stored, in which case it would be shown but it should be ignored. (You can modify this, look in ``tools/autodebugger.py``.)
|
||||
emcc verbose output
|
||||
===================
|
||||
|
||||
One use of the autodebugger is to quickly emit lots of logging output. You can then take a look and see if something weird pops up. Another use is for regressions, see below.
|
||||
Compiling with the :ref:`emcc -v <emcc-verbose>` option passes ``-v`` to LLVM and runs Emscripten's internal sanity checks on the toolchain.
|
||||
|
||||
AutoDebugger Regression Workflow
|
||||
---------------------------------
|
||||
The verbose mode also enables Emscripten's :ref:`debug mode <debugging-EMCC_DEBUG>` (with ``EMCC_DEBUG=1``) to generate intermediate files for the compiler’s various stages.
|
||||
|
||||
Fixing regressions is pretty easy with the autodebugger, using the following workflow:
|
||||
|
||||
- Compile the code using ``EMCC_AUTODEBUG=1`` in the environment.
|
||||
- Compile the code using ``EMCC_AUTODEBUG=1`` in the environment, again, but with a difference emcc setting etc., so that you now have one build before the regression and one after.
|
||||
- Run both versions, saving their output, then do a diff and investigate that. Any difference is likely the bug (other false positives could be things like the time, if something like ``clock()`` is called, which differs slightly between runs).
|
||||
.. _debugging-manual-debugging:
|
||||
|
||||
(You can also make the second build a native one using the llvm nativizer tool mentioned above - run it on the autodebugged .ll file, which EMCC_DEBUG=1 will emit in ``/tmp/emscripten_temp``. This helps find bugs in general and not just regressions, but has the same issues with the nativizer tool mentioned earlier.)
|
||||
Manual print debugging
|
||||
======================
|
||||
|
||||
|
||||
You can also manually instrument the source code with ``printf()`` statements, then compile and run the code to investigate issues.
|
||||
|
||||
Specific Issues
|
||||
If you have a good idea of the problem line you can add add ``print(new Error().stack)`` to the JavaScript to get a stack trace at that point. There is also :js:func:`stackTrace` which emits a stack trace and also tries to demangle C++ function names. Debug printouts can even execute arbitrary JavaScript.
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: cpp
|
||||
|
||||
function _addAndPrint($left, $right) {
|
||||
$left = $left | 0;
|
||||
$right = $right | 0;
|
||||
//---
|
||||
if ($left < $right) console.log('l<r at ' + stackTrace());
|
||||
//---
|
||||
_printAnInteger($left + $right | 0);
|
||||
}
|
||||
|
||||
|
||||
Disabling optimizations
|
||||
=======================
|
||||
|
||||
It can sometimes be useful to compile with either :ref:`LLVM <emcc-llvm-opts>` or :ref:`JavaScript <emcc-js-opts>` optimizations (only) disabled.
|
||||
|
||||
For example, the following command enables :ref:`-02 <emcc-O2>` optimization for both LLVM and JavaScript and :ref:`debugging-debug-information-g`, but then explicitly turns off the JavaScript optimizer.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./emcc -O2 --js-opts 0 -g4 tests/hello_world_loop.cpp
|
||||
|
||||
The result is code that can be more useful for debugging issues related to LLVM optimized code:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
function _main() {
|
||||
var label = 0;
|
||||
var $puts=_puts(((8)|0)); //@line 4 "tests/hello_world.c"
|
||||
return 1; //@line 5 "tests/hello_world.c"
|
||||
}
|
||||
|
||||
|
||||
|
||||
.. _debugging-emscripten-specific-issues:
|
||||
|
||||
Emscripten-specific issues
|
||||
==========================
|
||||
|
||||
Memory Alignment Issues
|
||||
-----------------------
|
||||
|
||||
``SAFE_HEAP`` will reveal memory alignment issues - where your code is assuming a higher alignment than appears in practice. Unaligned reads and writes can lead to incorrect results, as our typed array model of memory does not support them.
|
||||
The :ref:`Emscripten memory representation <emscripten-memory-model>` assumes loads and stores are aligned. Performing a normal load or store on an unaligned address can fail.
|
||||
|
||||
The best solution is to avoid unaligned reads and writes. Generally they occur as the result of undefined behavior.
|
||||
.. tip:: :ref:`SAFE_HEAP <debugging-SAFE-HEAP>` can be used to reveal memory alignment issues.
|
||||
|
||||
Generally it is best to avoid unaligned reads and writes — often they occur as the result of undefined behavior. In some cases, however, they are unavoidable. For example if the code to be ported reads an ``int`` from a packed structure in some pre-existing data format.
|
||||
|
||||
Emscripten supports unaligned reads and writes, but they will be much slower, and should be used only when absolutely necessary. To force an unaligned read or write you can:
|
||||
|
||||
- Manually read individual bytes and reconstruct the full value
|
||||
- Use the :c:type:`emscripten_align* <emscripten_align1_short>` typedefs, which define unaligned versions of the basic types (``short``, ``int``, ``float``, ``double``). All operations on those types are not fully aligned (use the ``1`` variants in most cases, which mean no alignment whatsoever).
|
||||
|
||||
In some cases, however, you may need unaligned reads and writes, for example to read an int from a packed structure in some pre-existing data format. To force an unaligned read or write (which will be slower, but work properly), you can either manually read individual bytes and reconstruct the full value, or use the ``emscripten_align*`` typedefs in ``emscripten.h``, which define unaligned versions of the basic types (short, int, float, double). All operations on those types are not fully aligned (use the ``1`` variants in most cases, which mean no alignment whatsoever). They are slower due to lack of alignment, though, so be sure to only use them when absolutely necessary.
|
||||
|
||||
Function Pointer Issues
|
||||
-----------------------
|
||||
|
||||
If you get an ``abort()`` from a function pointer call (``nullFunc`` or ``b0`` or ``b1`` or such, possibly with an error message saying "incorrect function pointer"), the issue is that a function pointer was called but it is invalid in that type.
|
||||
If you get an ``abort()`` from a function pointer call to ``nullFunc`` or ``b0`` or ``b1`` (possibly with an error message saying "incorrect function pointer"), the problem is that the function pointer was not found in the expected function pointer table when called.
|
||||
|
||||
It is undefined behavior to cast a function pointer to another type and call that (e.g., cast away the last parameter), but this does happen in real-world code, and is one possible cause for this error. In optimized Emscripten output, each function pointer type has a different table of entries, so you must call with the correct type to get the right behavior.
|
||||
.. note:: ``nullFunc`` is the function used to populate empty index entries in the function pointer tables (``b0``, ``b1`` are shorter names used for ``nullFunc`` in more optimized builds). A function pointer to an invalid index will call this function, which simply calls ``abort()``.
|
||||
|
||||
Another possible cause is a dereference of 0, like calling a method on a NULL pointer or such. That can be a bug in the code caused by any reason, but shows itself as a function pointer error (as just reading or writing to a NULL pointer will work, unlike in native builds - it is just function pointers that will always fail when NULL).
|
||||
There are several possible causes:
|
||||
|
||||
Building with ``-Werror`` (turn warnings into errors) can help here, as some cases of undefined behavior show warnings. If you can get your codebase to build with ``-Werror`` that might help.
|
||||
- Code is calling a function pointer that has been cast from another type (this is undefined behavior but it does happen in real-world code). In optimized Emscripten output, each function pointer type is stored in a separate table based on its original signature, so you *must* call a function pointer with that same signature to get the right behavior (see :ref:`portability-function-pointer-issues` in the code portability section for more information).
|
||||
- Code calls a method on a NULL pointer or dereferences 0. This sort of bug can be caused by any sort of coding error, but manifests as a function pointer error because the function can't be found in the expected table at runtime.
|
||||
|
||||
Use ``-s ASSERTIONS=2`` to get some useful information about the function pointer being called, and its type. Also useful is to look at the stack trace (may want to disable asm.js optimizations in Mozilla Firefox to see the best trace information) to see where in your code the error happens, then see which function should be called but isn't.
|
||||
In order to debug these sorts of issues:
|
||||
|
||||
SAFE_HEAP is also useful when debugging issues like this, as is disabling function pointer aliasing using ``ALIASING_FUNCTION_POINTERS=0``. When you build with ``-s SAFE_HEAP=1 -s ALIASING_FUNCTION_POINTERS=0`` then it should be impossible for a function pointer to be called with the wrong type without an error showing up.
|
||||
- Compile with ``-Werror``. This turns warnings into errors, which can be useful as some cases of undefined behavior would otherwise show warnings.
|
||||
- Use ``-s ASSERTIONS=2`` to get some useful information about the function pointer being called, and its type.
|
||||
- Look at the browser stack trace to see where the error occurs and which function should have been called.
|
||||
- Build with :ref:`SAFE_HEAP=1 <debugging-SAFE-HEAP>` and function pointer aliasing disabled (``ALIASING_FUNCTION_POINTERS=0``). This should make it impossible for a function pointer to be called with the wrong type without raising an error: ``-s SAFE_HEAP=1 -s ALIASING_FUNCTION_POINTERS=0``
|
||||
|
||||
|
||||
Another function pointer issue is when the wrong function is called. :ref:`SAFE_HEAP=1 <debugging-SAFE-HEAP>` can help with this as it detects some possible errors with function table accesses. ``ALIASING_FUNCTION_POINTERS=0`` is also useful as it ensures that every function pointer is a globally unique number (forcing a function call on the wrong table to call a missing function rather than potentially the wrong function).
|
||||
|
||||
Another possible problem with function pointers is that what appears to be the wrong function is called. Again, ``SAFE_HEAP`` can help with this as it detects some possible errors with function table accesses.
|
||||
|
||||
Infinite loops
|
||||
--------------
|
||||
|
||||
If your code hits an infinite loop, one easy way to see where that happens is to use a JavaScript profiler. In the Firefox profiler for example it is easy to see which code ran at what time, so if the code enters an infinite loop for a while (before the browser shows the slow script dialog and you quit it), you will see a block of code doing the same thing near the end of the profile.
|
||||
Infinite loops cause your page to hang. After a period the browser will notify the user that the page is stuck and offer to halt or close it.
|
||||
|
||||
If your code hits an infinite loop, one easy way to find the problem code is to use a *JavaScript profiler*. In the Firefox profiler, if the code enters an infinite loop you will see a block of code doing the same thing near the end of the profile.
|
||||
|
||||
.. note:: The :ref:`emscripten-runtime-environment-main-loop` may need to be re-coded if your application uses an infinite main loop.
|
||||
|
||||
|
||||
|
||||
Additional Tips
|
||||
===========================
|
||||
.. _debugging-autodebugger:
|
||||
|
||||
You can also do something similar to what the autodebugger does, manually - modify the original source code with some ``printf()``\ s, then compile and run that, to investigate issues.
|
||||
AutoDebugger
|
||||
============
|
||||
|
||||
The *AutoDebugger* is the 'nuclear option' for debugging Emscripten code.
|
||||
|
||||
.. warning:: This option is primarily intended for Emscripten core developers.
|
||||
|
||||
The *AutoDebugger* will rewrite the LLVM bitcode so it prints out each store to memory. You can then run the exact same LLVM bitcode compiled using `tools/nativize_llvm.py <https://github.com/kripken/emscripten/blob/master/tools/nativize_llvm.py>`_ (or in the :term:`LLVM interpreter`) and JavaScript, and compare the output.
|
||||
|
||||
The *AutoDebugger* can potentially find **any** problem in the generated code, so it is strictly more powerful than the ``CHECK_*`` settings and ``SAFE_HEAP``. One use of the *AutoDebugger* is to quickly emit lots of logging output, which can then be reviewed for odd behavior. The *AutoDebugger* is also particularly useful for :ref:`debugging regressions <debugging-autodebugger-regressions>`.
|
||||
|
||||
The *AutoDebugger* has some limitations:
|
||||
|
||||
- It generates a lot of output. Using *diff* can be very helpful for identifying changes.
|
||||
- It prints out simple numerical values rather than pointer addresses (because pointer addresses change between runs, and hence can't be compared). This is a limitation because sometimes inspection of addresses can show errors where the pointer address is 0 or impossibly large. It is possible to modify the tool to print out addresses as integers in ``tools/autodebugger.py``.
|
||||
|
||||
To run the *AutoDebugger*, compile with the environment variable ``EMCC_AUTODEBUG=1`` set. For example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Linux or Mac OS X
|
||||
EMCC_AUTODEBUG=1 ./emcc tests/hello_world.cpp -o hello.html
|
||||
|
||||
# Windows
|
||||
set EMCC_AUTODEBUG=1
|
||||
emcc tests/hello_world.cpp -o hello.html
|
||||
set EMCC_AUTODEBUG=0
|
||||
|
||||
|
||||
.. _debugging-autodebugger-regressions:
|
||||
|
||||
AutoDebugger Regression Workflow
|
||||
---------------------------------
|
||||
|
||||
Use the following workflow to find regressions with the *AutoDebugger*:
|
||||
|
||||
- Compile the working code with ``EMCC_AUTODEBUG=1`` set in the environment.
|
||||
- Compile the code using ``EMCC_AUTODEBUG=1`` in the environment again, but this time with the settings that cause the regression. Following this step we have one build before the regression and one after.
|
||||
- Run both versions of the compiled code and save their output.
|
||||
- Compare the output using a *diff* tool.
|
||||
|
||||
Any difference between the outputs is likely to be caused by the bug.
|
||||
|
||||
.. note:: False positives can be caused by calls to ``clock()``, which will differ slightly between runs.
|
||||
|
||||
You can also make native builds using the :term:`LLVM Nativizer` tool. This can be run on the autodebugged **.ll** file, which will be emitted in ``/tmp/emscripten_temp`` when ``EMCC_DEBUG=1`` is set.
|
||||
|
||||
.. note::
|
||||
|
||||
- The native build created using the :term:`LLVM Nativizer` will use native system libraries. Direct comparisons of output with Emscripten-compiled code can therefore be misleading.
|
||||
- Attempting to interpret code compiled with ``-g`` using the *LLVM Nativizer* or :term:`lli` may crash. So you may need to build once without ``-g`` for these tools, then build again with ``-g``. Or, use `tools/exec_llvm.py <https://github.com/kripken/emscripten/blob/master/tools/exec_llvm.py>`_ in Emscripten, which will run *lli* after cleaning out debug info.
|
||||
|
||||
Another useful tip is if you have a good idea of what line is problematic in generated .js, you can add ``print(new Error().stack)`` to get a stack trace there. There is also :js:func:`stackTrace` which emits a stack trace and also tries to demangle C++ function names.
|
||||
|
||||
Useful Links
|
||||
===========================
|
||||
============
|
||||
|
||||
`Blogpost about reading compiler output <http://mozakai.blogspot.com/2014/06/looking-through-emscripten-output.html>`_.
|
||||
- `Blogpost about reading compiler output <http://mozakai.blogspot.com/2014/06/looking-through-emscripten-output.html>`_.
|
||||
- `GDC 2014: Getting started with asm.js and Emscripten <http://people.mozilla.org/~lwagner/gdc-pres/gdc-2014.html#/20>`_ (Debugging slides).
|
||||
|
||||
Additional Help
|
||||
===========================
|
||||
Need help?
|
||||
==========
|
||||
|
||||
Of course, you can also ask the Emscripten devs for help. :) See links to IRC and the Google Group on the main project page.
|
||||
The :ref:`Emscripten Test Suite <running-emscripten-tests>` contains known-good examples of almost all functionality offered by Emscripten. If you have a problem, it is therefore a good idea to search the suite to determine whether test code with similar behavior is able to run.
|
||||
|
||||
If you've tried the ideas here and you need more help, then please :ref:`contact`.
|
||||
|
||||
.. todo:: **HamishW** Make sure that SAFE_HEAP is clearly documented, and ideally has a section we can link to from the rest of the document.
|
|
@ -1,3 +1,5 @@
|
|||
.. _portability-function-pointer-issues:
|
||||
|
||||
=======================
|
||||
Function Pointer Issues
|
||||
=======================
|
||||
|
@ -23,7 +25,7 @@ There are three general issues with function pointers:
|
|||
|
||||
#.
|
||||
|
||||
When using optimisation :ref:`-O2 <emcc-O2>` and above, comparing function pointers of different types can give false positives, and bugs with incorrect function pointers are potentially more misleading. To check if this is the cause of problems with your code, you can compile with `ALIASING_FUNCTION_POINTERS <https://github.com/kripken/emscripten/blob/master/src/settings.js#L201>`_ unset (``-s ALIASING_FUNCTION_POINTERS=0``).
|
||||
When using optimisation :ref:`-O2 <emcc-O2>` and above, comparing function pointers of different types can give false positives, and bugs with incorrect function pointers are potentially more misleading. To check if this is the cause of problems with your code, you can compile with `ALIASING_FUNCTION_POINTERS <https://github.com/kripken/emscripten/blob/master/src/settings.js#L209>`_ unset (``-s ALIASING_FUNCTION_POINTERS=0``).
|
||||
|
||||
.. note:: In **asm.js**, function pointers are stored within a function-type specific table (as in the ``FUNCTION_TABLE_ii`` example from before).
|
||||
|
||||
|
|
|
@ -90,6 +90,19 @@ Emscripten tools and dependencies
|
|||
|
||||
The Emscripten project is hosted on Github.
|
||||
|
||||
lli
|
||||
LLVM Interpreter
|
||||
The `LLVM interpreter (LLI) <http://llvm.org/releases/3.0/docs/CommandGuide/html/lli.html>`_ executes programs from :term:`LLVM` bitcode. This tool is not maintained and has odd errors and crashes.
|
||||
|
||||
Emscripten provides an alternative tool, the :term:`LLVM Nativizer`.
|
||||
|
||||
LLVM Nativizer
|
||||
The LLVM Nativizer (`tools/nativize_llvm.py <https://github.com/kripken/emscripten/blob/master/tools/nativize_llvm.py>`_) compiles LLVM bitcode to a native executable. This links to the host libraries, so comparisons of output with Emscripten builds will not necessarily be identical.
|
||||
|
||||
It performs a similar role to the :term:`LLVM Interpreter`.
|
||||
|
||||
.. note:: Sometimes the output of the this tool will crash or fail. This tool is intended for developers fixing bugs in Emscripten.
|
||||
|
||||
|
||||
SDK Terms
|
||||
=========
|
||||
|
|
|
@ -37,6 +37,8 @@ Options that are modified or new in *emcc* are listed below:
|
|||
|
||||
.. _emcc-compiler-optimization-options:
|
||||
|
||||
.. _emcc-O0:
|
||||
|
||||
``-O0``
|
||||
No optimizations (default). This is the recommended setting for starting to port a project, as it includes various assertions.
|
||||
|
||||
|
@ -47,8 +49,8 @@ Options that are modified or new in *emcc* are listed below:
|
|||
|
||||
.. note::
|
||||
|
||||
- For details on the affects of different opt levels, see ``apply_opt_level()`` in `tools/shared.py <https://github.com/kripken/emscripten/blob/master/tools/shared.py>`_ and also `src/settings.js <https://github.com/kripken/emscripten/blob/master/src/settings.js>`_.
|
||||
- To re-enable C++ exception catching, use ``-s DISABLE_EXCEPTION_CATCHING=0``.
|
||||
- For details on the effects of different optimization levels, see ``apply_opt_level()`` in `tools/shared.py <https://github.com/kripken/emscripten/blob/master/tools/shared.py>`_ and also `src/settings.js <https://github.com/kripken/emscripten/blob/master/src/settings.js>`_.
|
||||
- To re-enable C++ exception catching, use :ref:`-s DISABLE_EXCEPTION_CATCHING=0 <optimizing-code-exception-catching>`.
|
||||
|
||||
.. _emcc-O2:
|
||||
|
||||
|
@ -56,12 +58,16 @@ Options that are modified or new in *emcc* are listed below:
|
|||
Like ``-O1``, but with various JavaScript-level optimizations and LLVM ``-O3`` optimizations.
|
||||
|
||||
.. note:: This is the recommended setting for a release build, offering slower compilation time in return for the smallest and fastest output.
|
||||
|
||||
.. _emcc-Os:
|
||||
|
||||
``-Os``
|
||||
Like ``-O2``, but with extra optimizations for size.
|
||||
Like ``-O2``, but with extra optimizations that reduce code size at the expense of performance. This applies only for bitcode optimization (``-O2`` is used for JavaScript optimizations).
|
||||
|
||||
.. _emcc-Oz:
|
||||
|
||||
``-Oz``
|
||||
Like ``-Os``, but reduces code size even further.
|
||||
Like ``-Os``, but reduces code size even further. This applies only for bitcode optimization (``-O2`` is used for JavaScript optimizations).
|
||||
|
||||
.. _emcc-O3:
|
||||
|
||||
|
@ -98,27 +104,72 @@ Options that are modified or new in *emcc* are listed below:
|
|||
.. _emcc-g:
|
||||
|
||||
``-g``
|
||||
Use debug info.
|
||||
Preserve debug information.
|
||||
|
||||
- When compiling to bitcode, this is the same as in *Clang* and *gcc* (it adds debug information to the object files).
|
||||
- When compiling from source to JavaScript or bitcode to JavaScript, it is equivalent to ``-g3`` (discards LLVM debug info including C/C++ line numbers, but otherwise keeps as much debug information as possible). Use ``-g4`` to get line number debugging information in JavaScript.
|
||||
- When compiling from source to JavaScript or bitcode to JavaScript, it is equivalent to :ref:`-g3 <emcc-g3>` (discards LLVM debug info including C/C++ line numbers, but otherwise keeps as much debug information as possible). Use :ref:`-g4 <emcc-g4>` to get line number debugging information in JavaScript.
|
||||
|
||||
.. _emcc-gN:
|
||||
|
||||
``-g<level>``
|
||||
Controls how much debug information is kept when compiling from bitcode to JavaScript. Each of these levels builds on the previous:
|
||||
Controls how much debug information is kept when compiling from bitcode to JavaScript. Each level builds on the previous level:
|
||||
|
||||
- ``-g0``: Make no effort to keep code debuggable. Will discard LLVM debug information (default in ``O1`` and higher).
|
||||
- ``-g1``: Preserve (do not minify) whitespace.
|
||||
- ``-g2``: Preserve function names.
|
||||
- ``-g3``: Preserve variable names.
|
||||
-
|
||||
.. _emcc-g0:
|
||||
|
||||
``-g0``: Make no effort to keep code debuggable. Will discard LLVM debug information (this is done by default in :ref:`-01 <emcc-O1>` and higher).
|
||||
|
||||
-
|
||||
.. _emcc-g1:
|
||||
|
||||
``-g1``: Preserve whitespace (do not minify).
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
function a(a, b) {
|
||||
a = a | 0;
|
||||
b = b | 0;
|
||||
f(a + b | 0);
|
||||
}
|
||||
|
||||
-
|
||||
.. _emcc-g2:
|
||||
|
||||
``-g2``: Preserve function names.
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
function _addAndPrint(a, b) {
|
||||
a = a | 0;
|
||||
b = b | 0;
|
||||
_printAnInteger(a + b | 0); // _printAnInteger is human readable.
|
||||
}
|
||||
|
||||
-
|
||||
.. _emcc-g3:
|
||||
|
||||
``-g3``: Preserve variable names (this is the same as :ref:`-g <emcc-g>`).
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
function _addAndPrint($left, $right) {
|
||||
$left = $left | 0;
|
||||
$right = $right | 0;
|
||||
_printAnInteger($left + $right | 0);
|
||||
}
|
||||
|
||||
.. note:: Variable names in the output will not necessarily match the original variable names in source. They are, however, usually similar enough to infer the purpose of the variables.
|
||||
|
||||
.. _emcc-g4:
|
||||
|
||||
- ``-g4``: Preserve LLVM debug information. If ``-g`` was used when compiling the C/C++ sources, show line number debug comments, and generate source maps. This is the highest level of debuggability.
|
||||
- ``-g4``: Preserve LLVM debug information. This is the highest level of debuggability. If ``-g`` was used when compiling the C/C++ sources, this shows line number debug comments, and generates source maps.
|
||||
|
||||
.. note:: This may make compilation at optimization level ``-O1`` and above significantly slower, because JavaScript optimization will be limited to one core (default in ``-O0``).
|
||||
.. note::
|
||||
|
||||
- This debugging level may make compilation at optimization level :ref:`-O1 <emcc-O1>` and above significantly slower, because JavaScript optimization will be limited to one core (the default in ``-O0``).
|
||||
- Source maps allow you to view and debug the *C/C++ source code* in your browser's debugger! This works in Firefox, Chrome and Safari.
|
||||
|
||||
|
||||
.. _emcc-profiling:
|
||||
|
||||
``--profiling``
|
||||
|
@ -287,11 +338,13 @@ Options that are modified or new in *emcc* are listed below:
|
|||
|
||||
``--js-library <lib>``
|
||||
A JavaScript library to use in addition to those in Emscripten's core libraries (src/library_*).
|
||||
|
||||
|
||||
.. _emcc-verbose:
|
||||
|
||||
``-v``
|
||||
Turns on verbose output.
|
||||
|
||||
This will pass ``-v`` to *Clang*, and also enable ``EMCC_DEBUG`` (this gets intermediate files for the compiler’s various stages). It will also run Emscripten's internal sanity checks on the toolchain, etc.
|
||||
This will pass ``-v`` to *Clang*, and also enable ``EMCC_DEBUG`` to generate intermediate files for the compiler’s various stages. It will also run Emscripten's internal sanity checks on the toolchain, etc.
|
||||
|
||||
.. tip:: ``emcc -v`` is a useful tool for diagnosing errors. It works with or without other arguments.
|
||||
|
||||
|
@ -391,5 +444,10 @@ Search for 'os.environ' in `emcc <https://github.com/kripken/emscripten/blob/mas
|
|||
- ``-s GL_UNSAFE_OPTS=1``
|
||||
- ``-s GL_FFP_ONLY=1``
|
||||
|
||||
-
|
||||
- ASSERTIONS
|
||||
- SAFE_HEAP
|
||||
- AGGRESSIVE_VARIABLE_ELIMINATION=1
|
||||
- -s DISABLE_EXCEPTION_CATCHING=0.
|
||||
- INLINING_LIMIT=
|
||||
- OUTLINING_LIMIT
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче