Skip to content

Commit

Permalink
Reduce default stack size from 5Mb to 64Kb (#18191)
Browse files Browse the repository at this point in the history
See ChangeLog.md for rationale.
  • Loading branch information
sbc100 committed Nov 28, 2022
1 parent bdbf777 commit 157fcd4
Show file tree
Hide file tree
Showing 16 changed files with 95 additions and 75 deletions.
12 changes: 12 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,17 @@ See docs/process.md for more on how version tagging works.
-----------------------
- Add support for `-sEXPORT_ES6`/`*.mjs` on Node.js. (#17915)
- Idle workers in a PThread pool no longer prevent Node.js app from exiting. (#18227)
- The default `STACK_SIZE` was reduced from 5MB to 64KB. Projects that use more
than 64Kb of stack will now need specify `-sSTACK_SIZE` at link time. For
example, `-sSTACK_SIZE=5MB` can be used to restore the previous behaviour.
To aid in debugging, as of #18154, we now also place the stack first in memory
in debug builds so that overflows will be immediately detected, and result in
runtime errors. This change brings emscripten into line with `wasm-ld` and
wasi-sdk defaults, and also reduces memory usage by default. In general,
WebAssembly stack usage should be lower than on other platforms since a lot of
state normally stored on the stack is hidden within the runtime and does not
occupy linear memory at all. The default for `DEFAULT_PTHREAD_STACK_SIZE` was
also reduced from 2MB to 64KB to match.

3.1.26 - 11/17/22
-----------------
Expand All @@ -48,6 +59,7 @@ See docs/process.md for more on how version tagging works.
overflow will trap rather corrupting global data first). This should not
be a user-visible change (unless your program does something very odd such
depending on the specific location of stack data in memory). (#18154)
- Add support for `-sEXPORT_ES6`/`*.mjs` on Node.js. (#17915)

3.1.25 - 11/08/22
-----------------
Expand Down
8 changes: 5 additions & 3 deletions src/library.js
Original file line number Diff line number Diff line change
Expand Up @@ -3139,12 +3139,14 @@ mergeInto(LibraryManager.library, {
#if STACK_OVERFLOW_CHECK
// Used by wasm-emscripten-finalize to implement STACK_OVERFLOW_CHECK
__handle_stack_overflow__sig: 'vp',
__handle_stack_overflow__deps: ['emscripten_stack_get_base'],
__handle_stack_overflow__deps: ['emscripten_stack_get_base', 'emscripten_stack_get_end', '$ptrToString'],
__handle_stack_overflow: function(requested) {
requested = requested >>> 0;
var base = _emscripten_stack_get_base();
var end = _emscripten_stack_get_end();
abort('stack overflow (Attempt to set SP to ' + ptrToString(requested) +
', with stack limits [' + ptrToString(_emscripten_stack_get_end()) +
' - ' + ptrToString(_emscripten_stack_get_base()) + '])');
', with stack limits [' + ptrToString(end) + ' - ' + ptrToString(base) +
']). If you require more stack space build with -sSTACK_SIZE=<bytes>');
},
#endif
Expand Down
4 changes: 2 additions & 2 deletions src/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ var MEM_INIT_METHOD = false;
// assertions are on, we will assert on not exceeding this, otherwise,
// it will fail silently.
// [link]
var STACK_SIZE = 5*1024*1024;
var STACK_SIZE = 64*1024;

// What malloc()/free() to use, out of
// * dlmalloc - a powerful general-purpose malloc
Expand Down Expand Up @@ -1595,7 +1595,7 @@ var PTHREAD_POOL_DELAY_LOAD = false;
// those that have their addresses taken, or ones that are too large to fit as
// local vars in wasm code.
// [link]
var DEFAULT_PTHREAD_STACK_SIZE = 2*1024*1024;
var DEFAULT_PTHREAD_STACK_SIZE = 64*1024;

// True when building with --threadprofiler
// [link]
Expand Down
16 changes: 7 additions & 9 deletions test/browser/test_sdl_create_rgb_surface_from.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,25 +12,24 @@

#define width 600
#define height 450
uint8_t pixels[width * height * 4];

int main() {

uint8_t pixels[width * height * 4];
uint8_t *end = pixels + width * height * 4;
uint8_t *pixel = pixels;
SDL_Rect rect = {0, 0, width, height};

while (pixel != end) {
*pixel = (pixel - pixels) * 256 / (width * height * 4);
pixel++;
*pixel = (pixel - pixels) * 256 / (width * height * 4);
pixel++;
}

SDL_Init(SDL_INIT_VIDEO);
SDL_Surface *screen = SDL_SetVideoMode(width, height, 32, SDL_HWSURFACE);
SDL_Surface *image = SDL_CreateRGBSurfaceFrom(pixels, width, height, 32, width * 4,
0x000000ff,
0x0000ff00,
0x00ff0000,
SDL_Surface *image = SDL_CreateRGBSurfaceFrom(pixels, width, height, 32, width * 4,
0x000000ff,
0x0000ff00,
0x00ff0000,
0xff000000);

SDL_FillRect(screen, &rect, SDL_MapRGB(screen->format, 255, 0, 0));
Expand All @@ -40,6 +39,5 @@ int main() {
printf("There should be a red to white gradient\n");

SDL_Quit();

return 0;
}
47 changes: 23 additions & 24 deletions test/core/test_emmalloc_memory_statistics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,29 @@
#include <emscripten/emmalloc.h>

template<typename T>
T round_to_4k(T val) {
return (T)(((size_t)val + 4095) & ~4095);
T round_to_4k(T val){
return (T)(((size_t)val + 4095) & ~4095);
}

int main() {
void *ptr = malloc(32*1024*1024);
void *ptr2 = malloc(4*1024*1024);
void *ptr3 = malloc(64*1024*1024);
void *ptr4 = malloc(16*1024);
void *ptr5 = malloc(2*1024*1024);
printf("%ld\n", (long)(ptr && ptr2 && ptr3 && ptr4 && ptr5));
free(ptr2);
free(ptr4);
printf("validate_memory_regions: %d\n", emmalloc_validate_memory_regions());
printf("dynamic_heap_size: %zu\n", emmalloc_dynamic_heap_size());
printf("free_dynamic_memory: %zu\n", emmalloc_free_dynamic_memory());
size_t numFreeMemoryRegions = 0;
size_t freeMemorySizeMap[32];
numFreeMemoryRegions = emmalloc_compute_free_dynamic_memory_fragmentation_map(freeMemorySizeMap);
printf("numFreeMemoryRegions: %zu\n", numFreeMemoryRegions);
for (int i = 0; i < 32; ++i) {
printf("%zu ", freeMemorySizeMap[i]);
}
printf("\n");
printf("unclaimed_heap_memory: %zu\n", round_to_4k(emmalloc_unclaimed_heap_memory()));
return 0;
int main()
{
void *ptr = malloc(32*1024*1024);
void *ptr2 = malloc(4*1024*1024);
void *ptr3 = malloc(64*1024*1024);
void *ptr4 = malloc(16*1024);
void *ptr5 = malloc(2*1024*1024);
printf("valid allocs: %d\n", (int)(ptr && ptr2 && ptr3 && ptr4 && ptr5));
free(ptr2);
free(ptr4);
printf("emmalloc_validate_memory_regions: %d\n", emmalloc_validate_memory_regions());
printf("emmalloc_dynamic_heap_size : %zu\n", emmalloc_dynamic_heap_size());
printf("emmalloc_free_dynamic_memory : %zu\n", emmalloc_free_dynamic_memory());
size_t numFreeMemoryRegions = 0;
size_t freeMemorySizeMap[32];
numFreeMemoryRegions = emmalloc_compute_free_dynamic_memory_fragmentation_map(freeMemorySizeMap);
printf("numFreeMemoryRegions: %zu\n", numFreeMemoryRegions);
for(int i = 0; i < 32; ++i)
printf("%zu ", freeMemorySizeMap[i]);
printf("\n");
printf("emmalloc_unclaimed_heap_memory : %zu\n", round_to_4k(emmalloc_unclaimed_heap_memory()));
}
10 changes: 5 additions & 5 deletions test/core/test_emmalloc_memory_statistics.out
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
1
validate_memory_regions: 0
dynamic_heap_size: 106971424
free_dynamic_memory: 4210892
valid allocs: 1
emmalloc_validate_memory_regions: 0
emmalloc_dynamic_heap_size : 106971424
emmalloc_free_dynamic_memory : 4210892
numFreeMemoryRegions: 3
0 0 0 0 0 0 0 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
unclaimed_heap_memory: 21999616
emmalloc_unclaimed_heap_memory : 27176960
10 changes: 5 additions & 5 deletions test/core/test_emmalloc_memory_statistics64.out
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
1
validate_memory_regions: 0
dynamic_heap_size: 106971712
free_dynamic_memory: 4211104
valid allocs: 1
emmalloc_validate_memory_regions: 0
emmalloc_dynamic_heap_size : 106971712
emmalloc_free_dynamic_memory : 4211104
numFreeMemoryRegions: 3
0 0 0 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
unclaimed_heap_memory: 21999616
emmalloc_unclaimed_heap_memory : 27176960
28 changes: 14 additions & 14 deletions test/core/test_emmalloc_trim.out
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
heap size: 134217728
dynamic heap 0: 4096
free dynamic memory 0: 4096
unclaimed heap memory 0: 2142175232
sbrk 0: 0x501000
unclaimed heap memory 0: 2147352576
sbrk 0: 0x11000
1
dynamic heap 1: 37752832
free dynamic memory 1: 4096
unclaimed heap memory 1: 2104426496
sbrk 1: 0x2901000
unclaimed heap memory 1: 2109603840
sbrk 1: 0x2411000
1st trim: 1
dynamic heap 1: 37752832
free dynamic memory 1: 0
unclaimed heap memory 1: 2104426496
sbrk 1: 0x2901000
unclaimed heap memory 1: 2109603840
sbrk 1: 0x2411000
2nd trim: 0
dynamic heap 2: 37752832
free dynamic memory 2: 0
unclaimed heap memory 2: 2104426496
sbrk 2: 0x2901000
unclaimed heap memory 2: 2109603840
sbrk 2: 0x2411000
3rd trim: 1
dynamic heap 3: 33656832
free dynamic memory 3: 102400
unclaimed heap memory 3: 2104426496
sbrk 3: 0x2901000
unclaimed heap memory 3: 2109603840
sbrk 3: 0x2411000
4th trim: 0
dynamic heap 4: 33656832
free dynamic memory 4: 102400
unclaimed heap memory 4: 2104426496
sbrk 4: 0x2901000
unclaimed heap memory 4: 2109603840
sbrk 4: 0x2411000
5th trim: 1
dynamic heap 5: 33558528
free dynamic memory 5: 0
unclaimed heap memory 5: 2104426496
sbrk 5: 0x2901000
unclaimed heap memory 5: 2109603840
sbrk 5: 0x2411000
2 changes: 1 addition & 1 deletion test/core/test_memcpy3.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
int main() {
#define RUN(type) \
{ \
type buffer[TOTAL]; \
static type buffer[TOTAL]; \
volatile int seed = 123; \
TEST(1, type); \
TEST(2, type); \
Expand Down
2 changes: 1 addition & 1 deletion test/core/test_memorygrowth_geometric_step.out
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
Heap size before allocation: 16777216
Ptr: 1, value: 16843009, Heap size now: 101777408 (increase: 85000192 bytes)
Ptr: 1, value: 16843009, Heap size now: 96600064 (increase: 79822848 bytes)
2 changes: 1 addition & 1 deletion test/core/test_memset.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
int main() {
#define RUN(type) \
{ \
type buffer[TOTAL]; \
static type buffer[TOTAL]; \
volatile int seed = 123; \
TEST(1, type); \
TEST(2, type); \
Expand Down
9 changes: 5 additions & 4 deletions test/fs/test_mmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,12 @@ void test_mmap_shared_with_offset() {
assert(fd >= 0);
size_t offset = sysconf(_SC_PAGE_SIZE) * 2;

char buffer[offset + 33];
memset(buffer, 0, offset + 33);
fread(buffer, 1, offset + 32, fd);
char buffer[33];
memset(buffer, 0, 33);
fseek(fd, offset, SEEK_SET);
fread(buffer, 1, 32, fd);
// expect text written from mmap operation to appear at offset in the file
printf("yolo/sharedoffset.txt content=%s %zu\n", buffer + offset, offset);
printf("yolo/sharedoffset.txt content=%s %zu\n", buffer, offset);
fclose(fd);
}
}
Expand Down
3 changes: 2 additions & 1 deletion test/pthread/test_pthread_create_pthread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ static void *thread1_start(void *arg)
return NULL;
}

#define DEFAULT_STACK_SIZE (64*1024)
int main()
{
pthread_t thr;
Expand All @@ -43,7 +44,7 @@ int main()
void *stack_addr;
pthread_attr_getstack(&attr, &stack_addr, &stack_size);
printf("stack_size: %d, stack_addr: %p\n", (int)stack_size, stack_addr);
if (stack_size != 2*1024*1024 || stack_addr == NULL)
if (stack_size != DEFAULT_STACK_SIZE || stack_addr == NULL)
result = -100; // Report failure.

pthread_join(thr, NULL);
Expand Down
5 changes: 4 additions & 1 deletion test/test_browser.py
Original file line number Diff line number Diff line change
Expand Up @@ -1283,6 +1283,9 @@ def test_webgl_context_attributes(self):
temp_filepath = os.path.basename(filepath)
shutil.copyfile(filepath, temp_filepath)

# testAntiAliasing uses a window-sized buffer on the stack
self.set_setting('STACK_SIZE', '1MB')

# perform tests with attributes activated
self.btest_exit('test_webgl_context_attributes_glut.c', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED', '-DALPHA_ACTIVATED', '-lGL', '-lglut', '-lGLEW'])
self.btest_exit('test_webgl_context_attributes_sdl.c', args=['--js-library', 'check_webgl_attributes_support.js', '-DAA_ACTIVATED', '-DDEPTH_ACTIVATED', '-DSTENCIL_ACTIVATED', '-DALPHA_ACTIVATED', '-lGL', '-lSDL', '-lGLEW'])
Expand Down Expand Up @@ -3316,7 +3319,7 @@ def test_async_2(self):
# Error.stackTraceLimit default to 10 in chrome but this test relies on more
# than 40 stack frames being reported.
create_file('pre.js', 'Error.stackTraceLimit = 80;\n')
self.btest_exit('browser/async_2.cpp', args=['-O3', '--pre-js', 'pre.js', '-sASYNCIFY'])
self.btest_exit('browser/async_2.cpp', args=['-O3', '--pre-js', 'pre.js', '-sASYNCIFY', '-sSTACK_SIZE=1MB'])

def test_async_virtual(self):
for opts in [0, 3]:
Expand Down
7 changes: 4 additions & 3 deletions test/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -5333,6 +5333,7 @@ def test_printf(self):
# needs to flush stdio streams
self.emcc_args.append('-Wno-format')
self.set_setting('EXIT_RUNTIME')
self.set_setting('STACK_SIZE', '1MB')
self.do_run_in_out_file_test('printf/test.c')

def test_printf_2(self):
Expand Down Expand Up @@ -6608,7 +6609,7 @@ def test_sse2(self):
self.run_process([shared.CLANG_CXX, src, '-msse2', '-Wno-argument-outside-range', '-o', 'test_sse2', '-D_CRT_SECURE_NO_WARNINGS=1'] + clang_native.get_clang_native_args(), stdout=PIPE)
native_result = self.run_process('./test_sse2', stdout=PIPE).stdout

self.emcc_args += ['-I' + test_file('sse'), '-msse2', '-Wno-argument-outside-range']
self.emcc_args += ['-I' + test_file('sse'), '-msse2', '-Wno-argument-outside-range', '-sSTACK_SIZE=1MB']
self.maybe_closure()
self.do_runf(src, native_result)

Expand Down Expand Up @@ -6652,7 +6653,7 @@ def test_sse4_1(self):
self.run_process([shared.CLANG_CXX, src, '-msse4.1', '-Wno-argument-outside-range', '-o', 'test_sse4_1', '-D_CRT_SECURE_NO_WARNINGS=1'] + clang_native.get_clang_native_args(), stdout=PIPE)
native_result = self.run_process('./test_sse4_1', stdout=PIPE).stdout

self.emcc_args += ['-I' + test_file('sse'), '-msse4.1', '-Wno-argument-outside-range']
self.emcc_args += ['-I' + test_file('sse'), '-msse4.1', '-Wno-argument-outside-range', '-sSTACK_SIZE=1MB']
self.maybe_closure()
self.do_runf(src, native_result)

Expand Down Expand Up @@ -6683,7 +6684,7 @@ def test_avx(self):
self.run_process([shared.CLANG_CXX, src, '-mavx', '-Wno-argument-outside-range', '-o', 'test_avx', '-D_CRT_SECURE_NO_WARNINGS=1'] + clang_native.get_clang_native_args(), stdout=PIPE)
native_result = self.run_process('./test_avx', stdout=PIPE).stdout

self.emcc_args += ['-I' + test_file('sse'), '-mavx', '-Wno-argument-outside-range']
self.emcc_args += ['-I' + test_file('sse'), '-mavx', '-Wno-argument-outside-range', '-sSTACK_SIZE=1MB']
self.maybe_closure()
self.do_runf(src, native_result)

Expand Down
5 changes: 4 additions & 1 deletion test/test_other.py
Original file line number Diff line number Diff line change
Expand Up @@ -2652,6 +2652,9 @@ def test_embind(self, extra_args):
'--pre-js', test_file('embind/test.pre.js'),
'--post-js', test_file('embind/test.post.js'),
'-sWASM_ASYNC_COMPILATION=0',
# This test uses a `CustomSmartPtr` class which has 1MB of data embedded in
# it which means we need more stack space than normal.
'-sTOTAL_STACK=2MB',
'-sIN_TEST_HARNESS'] + args)

if '-sDYNAMIC_EXECUTION=0' in args:
Expand Down Expand Up @@ -5850,7 +5853,7 @@ def test_massive_alloc(self, wasm):
# just care about message regarding allocating over 1GB of memory
output = self.run_js('a.out.js')
if not wasm:
self.assertContained('Warning: Enlarging memory arrays, this is not fast! 16777216,1473314816\n', output)
self.assertContained('Warning: Enlarging memory arrays, this is not fast! 16777216,1468137472\n', output)

def test_failing_alloc(self):
for pre_fail, post_fail, opts in [
Expand Down

0 comments on commit 157fcd4

Please sign in to comment.