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

test_wrap_malloc currently failed under mimalloc #23090

Open
sbc100 opened this issue Dec 5, 2024 · 11 comments
Open

test_wrap_malloc currently failed under mimalloc #23090

sbc100 opened this issue Dec 5, 2024 · 11 comments

Comments

@sbc100
Copy link
Collaborator

sbc100 commented Dec 5, 2024

RuntimeError: Aborted(Cannot enlarge memory arrays to size 37867744 bytes (OOM). Either (1) compile with -sINITIAL_MEMORY=X with X higher than the current value 16908288, (2) compile with -sALLOW_MEMORY_GROWTH which allows increasing the size at runtime, or (3) if you want malloc to return NULL (0) instead of this abort, compile with -sABORTING_MALLOC=0)
    at abort (/tmp/emtest_nffk6s6d/emscripten_test_core0_8ivvzj_9/test_wrap_malloc.js:563:11)
    at abortOnCannotGrowMemory (/tmp/emtest_nffk6s6d/emscripten_test_core0_8ivvzj_9/test_wrap_malloc.js:1122:7)
    at _emscripten_resize_heap (/tmp/emtest_nffk6s6d/emscripten_test_core0_8ivvzj_9/test_wrap_malloc.js:1128:7)
    at test_wrap_malloc.wasm.sbrk (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[261]:0xc799)
    at test_wrap_malloc.wasm.claim_more_memory (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[233]:0xb85b)
    at test_wrap_malloc.wasm.emmalloc_memalign (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[234]:0xbcc1)
    at test_wrap_malloc.wasm._mi_prim_alloc (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[240]:0xc0cb)
    at test_wrap_malloc.wasm._mi_os_alloc_aligned (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[197]:0x93f7)
    at test_wrap_malloc.wasm.mi_reserve_os_memory_ex (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[103]:0x4e33)
    at test_wrap_malloc.wasm._mi_arena_alloc_aligned (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[101]:0x4c48)
    at test_wrap_malloc.wasm.mi_segment_alloc (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[283]:0xe1be)
    at test_wrap_malloc.wasm.mi_segments_page_alloc (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[282]:0xe038)
    at test_wrap_malloc.wasm._mi_segment_page_alloc (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[280]:0xda55)
    at test_wrap_malloc.wasm.mi_page_fresh_alloc (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[230]:0xb66f)
    at test_wrap_malloc.wasm.mi_find_page (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[227]:0xb4ed)
    at test_wrap_malloc.wasm._mi_malloc_generic (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[226]:0xaf01)
    at test_wrap_malloc.wasm.mi_malloc (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[66]:0x3610)
    at test_wrap_malloc.wasm.malloc (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[14]:0x71e)
    at test_wrap_malloc.wasm.__original_main (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[17]:0xa22)
    at test_wrap_malloc.wasm.main (wasm://wasm/test_wrap_malloc.wasm-00258b5e:wasm-function[18]:0xc29)
    at /tmp/emtest_nffk6s6d/emscripten_test_core0_8ivvzj_9/test_wrap_malloc.js:615:12
    at callMain (/tmp/emtest_nffk6s6d/emscripten_test_core0_8ivvzj_9/test_wrap_malloc.js:1640:15)
    at doRun (/tmp/emtest_nffk6s6d/emscripten_test_core0_8ivvzj_9/test_wrap_malloc.js:1690:23)
    at run (/tmp/emtest_nffk6s6d/emscripten_test_core0_8ivvzj_9/test_wrap_malloc.js:1703:5)
    at runCaller (/tmp/emtest_nffk6s6d/emscripten_test_core0_8ivvzj_9/test_wrap_malloc.js:1625:19)
    at removeRunDependency (/tmp/emtest_nffk6s6d/emscripten_test_core0_8ivvzj_9/test_wrap_malloc.js:533:7)
    at receiveInstance (/tmp/emtest_nffk6s6d/emscripten_test_core0_8ivvzj_9/test_wrap_malloc.js:739:5)
    at receiveInstantiationResult (/tmp/emtest_nffk6s6d/emscripten_test_core0_8ivvzj_9/test_wrap_malloc.js:757:5)
Thrown at:
    at abort (/tmp/emtest_nffk6s6d/emscripten_test_core0_8ivvzj_9/test_wrap_malloc.js:563:11)
    at abortOnCannotGrowMemory (/tmp/emtest_nffk6s6d/emscripten_test_core0_8ivvzj_9/test_wrap_malloc.js:1122:7)
    at _emscripten_resize_heap (/tmp/emtest_nffk6s6d/emscripten_test_core0_8ivvzj_9/test_wrap_malloc.js:1128:7)
    at $sbrk (wasm://wasm/test_wrap_malloc.wasm-00258b5e:1:51098)
    at $claim_more_memory (wasm://wasm/test_wrap_malloc.wasm-00258b5e:1:47196)
    at $emmalloc_memalign (wasm://wasm/test_wrap_malloc.wasm-00258b5e:1:48322)
    at $_mi_prim_alloc (wasm://wasm/test_wrap_malloc.wasm-00258b5e:1:49356)
    at $_mi_os_alloc_aligned (wasm://wasm/test_wrap_malloc.wasm-00258b5e:1:37880)
    at $mi_reserve_os_memory_ex (wasm://wasm/test_wrap_malloc.wasm-00258b5e:1:20020)
    at $_mi_arena_alloc_aligned (wasm://wasm/test_wrap_malloc.wasm-00258b5e:1:19529)
@kripken
Copy link
Member

kripken commented Dec 5, 2024

Does increasing INITIAL_MEMORY fix this? It is expected that mimalloc take more memory than other allocators.

@sbc100
Copy link
Collaborator Author

sbc100 commented Dec 5, 2024

IIRC I decreased the memory used in the test from 1mb for loop to just 10k per loop and it still failed.

@kleisauke
Copy link
Collaborator

It seems to work without any issues when using -sINITIAL_MEMORY=64MB.

--- a/test/test_core.py
+++ b/test/test_core.py
@@ -8597,8 +8597,7 @@ NODEFS is no longer included by default; build with -lnodefs.js
   @parameterized({
     '': ([],),
     'emmalloc': (['-sMALLOC=emmalloc'],),
-    # FIXME(https://github.com/emscripten-core/emscripten/issues/23090)
-    # 'mimalloc': (['-sMALLOC=mimalloc'],),
+    'mimalloc': (['-sMALLOC=mimalloc', '-sINITIAL_MEMORY=64MB'],),
   })
   def test_wrap_malloc(self, args):
     self.do_runf('core/test_wrap_malloc.c', 'OK.', emcc_args=args)

@sbc100
Copy link
Collaborator Author

sbc100 commented Dec 6, 2024

Any idea why mimalloc would need twice as much memory as the other allocators?

Any idea why changing the test to do void *ptr = malloc(1024 * 10); instead if void *ptr = malloc(1024 * 1024) doesn't also fix it? Surely allocating 100 times less memory should also fix it?

@sbc100
Copy link
Collaborator Author

sbc100 commented Dec 6, 2024

See #23091

@sbc100
Copy link
Collaborator Author

sbc100 commented Dec 6, 2024

The error seems to occur on the very first allocation...

@kleisauke
Copy link
Collaborator

It appears that -sINITIAL_MEMORY=37MB also works correctly. Interestingly, mimalloc calls emmalloc_memalign(4 * 1024 * 1024, 32 * 1024 * 1024), which results in a 36MiB allocation due to the following code in emmalloc:

// Take into account the alignment as well. For typical alignment we don't
// need to add anything here (so we do nothing if the alignment is equal to
// MALLOC_ALIGNMENT), but it can matter if the alignment is very high. In that
// case, not adding the alignment can lead to this sbrk not giving us enough
// (in which case, the next attempt fails and will sbrk the same amount again,
// potentially allocating a lot more memory than necessary).
//
// Note that this is not necessarily optimal, as the extra allocation size for
// the alignment might not be needed (if we are lucky and already aligned),
// and even if it helps us allocate it will not immediately be ready for reuse
// (as it will be added to the currently-in-use region before us, so it is not
// in a free list). As a compromise however it seems reasonable in practice as
// a way to handle large aligned regions to avoid even worse waste.
if (alignment > MALLOC_ALIGNMENT) {
numBytesToClaim += alignment;
}

You would expect that -sINITIAL_MEMORY=36MB would suffice in this case, but emmalloc performs a small allocation at initialization:

// Start with a tiny dynamic region.
claim_more_memory(3*sizeof(Region));

initialize_emmalloc_heap()
claim_more_memory(numBytes=48)
claim_more_memory: claimed 0x0001d800 - 0x0001d830 (48 bytes) via sbrk()
claim_more_memory: sbrk() returned a disjoint region to last root region, some external code must have sbrk()ed outside emmalloc(). Creating a new root region
allocate_memory(align=4194304, size=33554432 bytes)
claim_more_memory(numBytes=37748784)
claim_more_memory: claimed 0x0001d830 - 0x0241d860 (37748784 bytes) via sbrk()
claim_more_memory: sbrk() returned a region contiguous to last root region, expanding the existing root region
allocate_memory(align=4194304, size=33554432 bytes)
attempt_allocate(freeRegion=0x0001d810,alignment=4194304,size=33554432)
attempt_allocate - succeeded allocating memory, region ptr=0x003ffffc, align=4194304, payload size=33554432 bytes)
...

With PR #23037, this test case also works with -sINITIAL_MEMORY=35MB (i.e. mimalloc calls emmalloc_memalign(2 * 1024 * 1024, 32 * 1024 * 1024) instead)

@@ -1,12 +1,12 @@
 initialize_emmalloc_heap()
 claim_more_memory(numBytes=48)
-claim_more_memory: claimed 0x0001d800 - 0x0001d830 (48 bytes) via sbrk()
+claim_more_memory: claimed 0x0001d840 - 0x0001d870 (48 bytes) via sbrk()
 claim_more_memory: sbrk() returned a disjoint region to last root region, some external code must have sbrk()ed outside emmalloc(). Creating a new root region
-allocate_memory(align=4194304, size=33554432 bytes)
-claim_more_memory(numBytes=37748784)
-claim_more_memory: claimed 0x0001d830 - 0x0241d860 (37748784 bytes) via sbrk()
+allocate_memory(align=2097152, size=33554432 bytes)
+claim_more_memory(numBytes=35651632)
+claim_more_memory: claimed 0x0001d870 - 0x0221d8a0 (35651632 bytes) via sbrk()
 claim_more_memory: sbrk() returned a region contiguous to last root region, expanding the existing root region
-allocate_memory(align=4194304, size=33554432 bytes)
-attempt_allocate(freeRegion=0x0001d810,alignment=4194304,size=33554432)
-attempt_allocate - succeeded allocating memory, region ptr=0x003ffffc, align=4194304, payload size=33554432 bytes)
+allocate_memory(align=2097152, size=33554432 bytes)
+attempt_allocate(freeRegion=0x0001d850,alignment=2097152,size=33554432)
+attempt_allocate - succeeded allocating memory, region ptr=0x001ffffc, align=2097152, payload size=33554432 bytes)
 

@sbc100
Copy link
Collaborator Author

sbc100 commented Dec 9, 2024

Even changing the test to only allocate 20k and the error seems to persist. i.e void *ptr = malloc(1024); in the loop. That seems bad.`

@sbc100
Copy link
Collaborator Author

sbc100 commented Dec 9, 2024

Actually that test frees the memory within the loop so the peak allocation should never be more than 1Mb or so. So this is certainly a bug in our mimalloc implementation and not something that should require the test to be updated.

@kleisauke
Copy link
Collaborator

By default, mimalloc preallocates a 32MiB memory arena on wasm32 to ensure memory is reused more effectively.

{ 128L*1024L, UNINIT, MI_OPTION(arena_reserve) }, // =128MiB on 32-bit

if (!_mi_os_has_virtual_reserve()) {
arena_reserve = arena_reserve/4; // be conservative if virtual reserve is not supported (for WASM for example)
}

@sbc100
Copy link
Collaborator Author

sbc100 commented Dec 9, 2024

By default, mimalloc preallocates a 32MiB memory arena on wasm32 to ensure memory is reused more effectively.

{ 128L*1024L, UNINIT, MI_OPTION(arena_reserve) }, // =128MiB on 32-bit

if (!_mi_os_has_virtual_reserve()) {
arena_reserve = arena_reserve/4; // be conservative if virtual reserve is not supported (for WASM for example)
}

But the default value for INITIAL_HEAP is 16MiB, so this sounds like it would simply fail in the default case (i.e. default memory size an non-growable). Do we not have tests that verify mimalloc works in this simple/default configuration?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants