memoryprofiler.js: A memory usage tracker for Emscripten apps.

3,514 views
Skip to first unread message

Jukka Jylänki

unread,
Sep 26, 2013, 5:28:22 PM9/26/13
to emscripte...@googlegroups.com
Hi,

I got caught by the season flu, and I thought I'd do something fun for a change, so here goes.

Memoryprofiler.js is a tool that integrates to Emscripten-built .html applications, and it tracks the various Emscripten memory area uses, and draws a graph of memory fragmentation in the Emscripten HEAP.

It hooks into the malloc(), free() and Runtime.stackAlloc() functions of the Emscripten runtime, and captures the memory usage as it happens.


A quick glossary of the related terms if you are not yet familiar with them:

HEAP: This is the single large memory blob that the Emscripten application allocates at startup, and is all the memory that the Emscripten application ever sees. The STATIC, STACK and DYNAMIC memory areas are allocated inside this chunk.

STATIC: This memory area contains constants and globals allocated at application startup time. Its size never changes at runtime. The STATIC memory area is in the lowest part of the Emscripten HEAP.

STACK: This is the application function call stack. Note that unlike the X86 stack that grows downwards, the Emscripten stack grows up. The profiler tracks how much space is used in the stack during the time stack and heap allocations occur, but note that it is only approximate - not all stack usage can be captured.

DYNAMIC: The memory area for dynamic heap allocations. This is the pool where memory is taken from when operator new or malloc is called.

As is readily visible in the map that gets graphed, the memory layout inside HEAP looks like

(address 0) [ STATIC | STACK | DYNAMIC | empty ] (top of HEAP)

The empty space between the top of the DYNAMIC area and the end of HEAP is unused, but fully reserved for the DYNAMIC area to grow into (via a page allocation operation from a function _sbrk). The total amount of memory the application can allocate is the sum of the empty area
plus the amount of free memory in DYNAMIC (minus fragmentation of the HEAP in DYNAMIC).

To embed memoryprofiler.js to your own builds:

1. Download https://dl.dropboxusercontent.com/u/40949268/emcc/memoryprofiler/memoryprofiler.js and place it next to your built Emscripten .html file.
2. Add a line "<script src='memoryprofiler.js'></script>" to your application .html file to link memoryprofiler.js to it.
3. In the Module properties of your application .html file, add a preRun call to memoryprofiler initialization function 'memoryprofiler_add_hooks()'. That is, replace the default line in Module that reads

preRun: []

with

preRun: [memoryprofiler_add_hooks]

and reopen the page. That's it!

To make steps 2. and 3. persist between builds, you can add the <script> tag and the preRun dependency to your custom shell file (copy the provided shell.html in emscripten source directory to your project and make the changes there), and use --shell-file my_shell_with_profiler.html at Emscripten link time to use that shell instead.

Configuration:

There are a few items you can configure in the profiler. Configuration occurs by directly editing the file memoryprofiler.js. See the variables

MEMORYPROFILER_DETAILED_HEAP_USAGE MEMORYPROFILER_TRACK_CALLSTACK_MIN_SIZE MEMORYPROFILER_HOOK_STACKALLOC
MEMORYPROFILER_UI_UPDATE_INTERVAL 

and their documentation in top of the file itself.

Hope it works!
   Jukka

Floh

unread,
Sep 27, 2013, 4:51:18 PM9/27/13
to emscripte...@googlegroups.com
Wow, that's some cool stuff :) I'll try to play with it over the weekend.
-Floh.

wolfviking0

unread,
Oct 1, 2013, 4:16:11 PM10/1/13
to emscripte...@googlegroups.com
Hi, very nice tool, I am playing with and very easy to add it, I hope try it soon with Unigine.

I have sometime an error on Safari / WebKit : TypeError: 'undefined' is not an object (evaluating 'new Error().stack.toString')
line 89 :  var loc = new Error().stack.toString();

Tony

Jukka Jylänki

unread,
Oct 2, 2013, 9:52:44 AM10/2/13
to emscripte...@googlegroups.com
Thanks for testing Floh and wolfviking0! 

I noticed the same on IE, neither of those browsers has the .stack member variable, so I added an update that detects it and disables the callstack walking if so.

I also noticed that the VFS allocations were not detected. I added a new feature that tracks which allocations come from the preRun stage (from VFS allocs), and graph those in orange, which will most likely show the amount of memory that the files in the virtual filesystem take up. That detection is not quite perfect, I think I'd need to write some helpers in library_fs.js to do it accurately, but that would make memoryprofiler.js a not-so-drop-in to use. Let me know if you find bugs there.

The updated version is available from the same link - https://dl.dropboxusercontent.com/u/40949268/emcc/memoryprofiler/memoryprofiler.js .

   Jukka



2013/10/1 wolfviking0 <anthon...@gmail.com>

--
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/groups/opt_out.

wolfviking0

unread,
Oct 7, 2013, 3:03:08 AM10/7/13
to emscripte...@googlegroups.com
Hi JJ,

Your last version is working well for me on WebKit.

Thanks.

PS: May be just one suggestion, add the color for the legend will be nice (not just text description).


Jukka Jylänki

unread,
Nov 12, 2013, 11:28:35 AM11/12/13
to emscripte...@googlegroups.com
Some updates to the memory profiler: (download from https://dl.dropboxusercontent.com/u/40949268/emcc/memoryprofiler/memoryprofiler.js )

 - The profiler will now also print the amount of memory consumed by audio clips you have loaded to the OpenAL audio backend, which are stored outside the Emscripten HEAP.
 - Added a color legend, thanks Floh for the suggestion :)
 - Added a mechanism for tracking currently allocated pointers by callstack. You can use this to detect running memory leaks or taking a delta of allocations between two times as follows:
     - tick the checkbox "Print allocation statistics by callstack to html log" at time A.
     - run the page for a while.
     - untick the same checkbox at time B.
     - the log at the end of the page will show all pointers that were allocated between times A to B and are still alive, grouped by callstack.

See a running demo at https://dl.dropboxusercontent.com/u/40949268/emcc/memoryprofiler/Geometry_d.html , although that might not be the best example, since it does very few allocations and does not leak.

Known limitations:
  - If you used a custom <script> tag to preload the VFS, the profiler will show the space taken up by the VFS in green, not orange, i.e. the profiler will not understand that it was allocated by the VFS.
  - Detailed memory tracking is not available if compiled under asm.js. This is because it is not possible to inject custom replacements to malloc() and free() after they were compiled to asm.js.
  - If you compiled with the --no-heap-copy linker flag, the VFS will not be seen by the profiler at all. Use e.g. Firefox about:memory tab to see the whole browser memory consumption.
  - Call stack demangling with the allocated pointer logging gets the symbols confused at times, only partially demanling some of the names.

Hope you find some use for it,
   Jukka


2013/10/7 wolfviking0 <anthon...@gmail.com>

Emerson Knapp

unread,
Jan 16, 2014, 8:55:04 PM1/16/14
to emscripte...@googlegroups.com
Hi,

Will this work with .js outputs from Emscripten as well? If so, my question follows.

I'm trying to use the memoryprofiler, I have added memoryprofiler_add_hooks to my .js output.
However, in callRuntimeCallbacks, when it calls memoryprofiler_add_hooks(), I get 'Uncaught ReferenceError: _malloc is not defined'
If I try 'console.log(_malloc)' in callRuntimeCallbacks on the line before they call the callback, it prints out fine, so it is available there. But it seems like it is not available in the scope of memoryprofiler_add_hooks.

Do you have any ideas why this is happening?

Thank you,
Emerson


2013/10/7 wolfviking0 <anthon...@gmail.com>
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.

Marco Trivellato

unread,
Jul 28, 2016, 8:44:33 AM7/28/16
to emscripten-discuss
Any idea if this profiler still works with recent versions of Emscripten ?


2013/10/7 wolfviking0 <anthon...@gmail.com>
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.

Alon Zakai

unread,
Jul 28, 2016, 4:10:27 PM7/28/16
to emscripten-discuss
Jukka would know for sure, but it should, there is a test in the suite, runnable with

./tests/runner.py interactive.test_cpuprofiler_memoryprofiler

that seems to pass. (Although, maybe some details have changed since these posts, so maybe looking in the test code can help.)



2013/10/7 wolfviking0 <anthon...@gmail.com>

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/groups/opt_out.

--
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.

juj j

unread,
Aug 1, 2016, 6:17:23 AM8/1/16
to emscripte...@googlegroups.com
This tool should definitely still work, only the --memoryprofiler linker flag should be needed, after which the profiler tool should appear on the page automatically at page startup. Are you seeing some issues?

One issue I've seen is that sometimes customized page style CSS layouts have caused the content of the memoryprofiler div appear outside the visible screen, and e.g. with overflow:hidden; style on the page, user wouldn't be able to scroll to it. If the layout of the memory profiler looks odd, try clearing CSS styles on the output page.

Marco Trivellato

unread,
Aug 1, 2016, 12:22:01 PM8/1/16
to emscripte...@googlegroups.com
Hi Alon and Jukka,

it turns out I just had to use an up-to-date memoryprofiler.js

thanks,
Marco

You received this message because you are subscribed to a topic in the Google Groups "emscripten-discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/emscripten-discuss/HtAzVposlX4/unsubscribe.
To unsubscribe from this group and all its topics, send an email to emscripten-disc...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Marco Trivellato <mar...@unity3d.com>
Unity Technologies

שחר לנגבהיים

unread,
Dec 8, 2019, 4:07:11 AM12/8/19
to emscripten-discuss
Hi, the Dropbox link no longer works. Is there a similar tool available?

Alon Zakai

unread,
Dec 8, 2019, 10:45:14 AM12/8/19
to emscripte...@googlegroups.com
I believe this landed as the --memoryprofiler option. Some minimal docs on https://emscripten.org/docs/tools_reference/emcc.html

‪On Sun, Dec 8, 2019 at 1:07 AM ‫שחר לנגבהיים‬‎ <nih...@gmail.com> wrote:‬
Hi, the Dropbox link no longer works. Is there a similar tool available?

--
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.
Reply all
Reply to author
Forward
0 new messages