Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reduce default stack size from 5MB to 64KB #18191

Merged
merged 1 commit into from
Nov 28, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this line added by accident? It's still under 3.1.27 as well.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, well spotted. Bad merge I assume


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