Skip to content

Commit

Permalink
emmalloc option (#6249)
Browse files Browse the repository at this point in the history
This adds a MALLOC option, where the user can pick which malloc/free implementation to use. The options are the existing dlmalloc, still the default, and the new emmalloc, which is about 1/3 the size. In small programs this can be very significant.

Performance-wise, emmalloc is small because it is very simple: all allocations are 8-byte aligned and multiples of, and there is no pooling, both of which are necessary to do well on huge amounts of tiny allocations. Because of that, it's 35% slower on the havlak benchmark (which allocates tons of 12-24 size areas, an AST of small nodes) and 10% slower on lua-binarytrees (apparently each lua object is a separate allocation, and there's an AST of small nodes there too...). But on all other benchmarks the only noticeable difference is smaller code size.

This PR does two other noticeable changes:

 * Our sbrk used to align. The spec doesn't say it needs to, and it's redundant as dlmalloc and emmalloc check the alignment anyhow. So this PR removes that.

 * I noticed that building dlmalloc with NDEBUG for opt builds is better. So this PR makes dlmalloc a little smaller as well.
  • Loading branch information
kripken committed Mar 8, 2018
1 parent 46faeee commit 78d3f20
Show file tree
Hide file tree
Showing 13 changed files with 1,774 additions and 46 deletions.
28 changes: 19 additions & 9 deletions embuilder.py
Expand Up @@ -27,8 +27,12 @@
build libc
libc-mt
emmalloc
emmalloc_debug
dlmalloc
dlmalloc_debug
dlmalloc_threadsafe
dlmalloc_threadsafe_debug
pthreads
libcxx
libcxx_noexcept
Expand Down Expand Up @@ -88,7 +92,7 @@
}
'''

SYSTEM_TASKS = ['compiler-rt', 'libc', 'libc-mt', 'dlmalloc', 'dlmalloc_threadsafe', 'pthreads', 'dlmalloc_debug', 'dlmalloc_threadsafe_debug', 'libcxx', 'libcxx_noexcept', 'libcxxabi', 'html5']
SYSTEM_TASKS = ['compiler-rt', 'libc', 'libc-mt', 'emmalloc', 'emmalloc_debug', 'dlmalloc', 'dlmalloc_threadsafe', 'pthreads', 'dlmalloc_debug', 'dlmalloc_threadsafe_debug', 'libcxx', 'libcxx_noexcept', 'libcxxabi', 'html5']
USER_TASKS = ['al', 'gl', 'binaryen', 'bullet', 'freetype', 'libpng', 'ogg', 'sdl2', 'sdl2-image', 'sdl2-ttf', 'sdl2-net', 'vorbis', 'zlib']

temp_files = shared.configuration.get_temp_files()
Expand Down Expand Up @@ -170,16 +174,22 @@ def build_port(port_name, lib_name, params):
return 0;
}
''', ['compiler-rt.a'])
elif what in ('libc', 'dlmalloc'):
build(C_WITH_MALLOC, ['libc.bc', 'dlmalloc.bc'])
elif what == 'wasm-libc':
build(C_WITH_STDLIB, ['wasm-libc.bc'], ['-s', 'WASM=1'])
elif what in ('libc-mt', 'pthreads', 'dlmalloc_threadsafe'):
build(C_WITH_MALLOC, ['libc-mt.bc', 'dlmalloc_threadsafe.bc', 'pthreads.bc'], ['-s', 'USE_PTHREADS=1'])
elif what == 'libc':
build(C_WITH_MALLOC, ['libc.bc'])
elif what == 'emmalloc':
build(C_WITH_MALLOC, ['emmalloc.bc'], ['-s', 'MALLOC="emmalloc"'])
elif what == 'emmalloc_debug':
build(C_WITH_MALLOC, ['emmalloc_debug.bc'], ['-s', 'MALLOC="emmalloc"', '-g'])
elif what == 'dlmalloc':
build(C_WITH_MALLOC, ['dlmalloc.bc'], ['-s', 'MALLOC="dlmalloc"'])
elif what == 'dlmalloc_debug':
build(C_WITH_MALLOC, ['dlmalloc_debug.bc'], ['-g'])
build(C_WITH_MALLOC, ['dlmalloc_debug.bc'], ['-g', '-s', 'MALLOC="dlmalloc"'])
elif what == 'dlmalloc_threadsafe_debug':
build(C_WITH_MALLOC, ['dlmalloc_threadsafe_debug.bc'], ['-g', '-s', 'USE_PTHREADS=1'])
build(C_WITH_MALLOC, ['dlmalloc_threadsafe_debug.bc'], ['-g', '-s', 'USE_PTHREADS=1', '-s', 'MALLOC="dlmalloc"'])
elif what in ('dlmalloc_threadsafe', 'libc-mt', 'pthreads'):
build(C_WITH_MALLOC, ['libc-mt.bc', 'dlmalloc_threadsafe.bc', 'pthreads.bc'], ['-s', 'USE_PTHREADS=1', '-s', 'MALLOC="dlmalloc"'])
elif what == 'wasm-libc':
build(C_WITH_STDLIB, ['wasm-libc.bc'], ['-s', 'WASM=1'])
elif what == 'libcxx':
build(CXX_WITH_STDLIB, ['libcxx.a'])
elif what == 'libcxx_noexcept':
Expand Down
1 change: 0 additions & 1 deletion src/library.js
Expand Up @@ -448,7 +448,6 @@ LibraryManager.library = {
var oldDynamicTopOnChange = 0;
var newDynamicTop = 0;
var totalMemory = 0;
increment = ((increment + 15) & -16)|0;
#if USE_PTHREADS
totalMemory = getTotalMemory()|0;

Expand Down
11 changes: 10 additions & 1 deletion src/settings.js
Expand Up @@ -62,6 +62,15 @@ var TOTAL_STACK = 5*1024*1024; // The total stack size. There is no way to enlar
var TOTAL_MEMORY = 16777216; // The total amount of memory to use. Using more memory than this will
// cause us to expand the heap, which can be costly with typed arrays:
// we need to copy the old heap into a new one in that case.
var MALLOC = "dlmalloc"; // What malloc()/free() to use, out of
// * dlmalloc - a powerful general-purpose malloc
// * emmalloc - a simple and compact malloc designed for emscripten
// dlmalloc is necessary for multithreading, split memory, and other special
// modes, and will be used automatically in those cases.
// In general, if you don't need one of those special modes, and if you don't
// allocate very many small objects, you should use emmalloc since it's
// smaller. Otherwise, if you do allocate many small objects, dlmalloc
// is usually worth the extra size.
var ABORTING_MALLOC = 1; // If 1, then when malloc would fail we abort(). This is nonstandard behavior,
// but makes sense for the web since we have a fixed amount of memory that
// must all be allocated up front, and so (a) failing mallocs are much more
Expand Down Expand Up @@ -440,7 +449,7 @@ var INCLUDE_FULL_LIBRARY = 0; // Include all JS library functions instead of the
// Note that this only applies to js libraries, *not* C. You
// will need the main file to include all needed C libraries.
// For example, if a module uses malloc or new, you will
// need to use those in the main file too to pull in dlmalloc
// need to use those in the main file too to pull in malloc
// for use by the module.

var SHELL_FILE = 0; // set this to a string to override the shell file used
Expand Down

0 comments on commit 78d3f20

Please sign in to comment.