Skip to content

Commit

Permalink
[wasm] stop using mmap/munmap (#108512)
Browse files Browse the repository at this point in the history
  • Loading branch information
pavelsavara authored Oct 24, 2024
1 parent 3db28cd commit a3fe47e
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 618 deletions.
1 change: 1 addition & 0 deletions src/mono/browser/browser.proj
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@
<EmccExportedFunction Include="_malloc" />
<EmccExportedFunction Include="_sbrk" />
<EmccExportedFunction Include="_memalign" />
<EmccExportedFunction Include="_posix_memalign" />
<EmccExportedFunction Include="_memset" />
<EmccExportedFunction Include="_ntohs" />
<EmccExportedFunction Include="stackAlloc" />
Expand Down
10 changes: 10 additions & 0 deletions src/mono/mono/sgen/sgen-los.c
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,12 @@ get_los_section_memory (size_t size)
section->next = los_sections;
los_sections = section;

#ifdef HOST_WASM
// on WASM there is no mmap and alignment has large overhead
sgen_los_memory_usage_total += LOS_SECTION_SIZE + LOS_SECTION_SIZE;
#else
sgen_los_memory_usage_total += LOS_SECTION_SIZE;
#endif
++los_num_sections;

goto retry;
Expand Down Expand Up @@ -542,7 +547,12 @@ sgen_los_sweep (void)
sgen_memgov_release_space (LOS_SECTION_SIZE, SPACE_LOS);
section = next;
--los_num_sections;
#ifdef HOST_WASM
// on WASM there is no mmap and alignment has large overhead
sgen_los_memory_usage_total -= LOS_SECTION_SIZE + LOS_SECTION_SIZE;
#else
sgen_los_memory_usage_total -= LOS_SECTION_SIZE;
#endif
continue;
}

Expand Down
9 changes: 6 additions & 3 deletions src/mono/mono/sgen/sgen-marksweep.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,13 @@ static int ms_block_size;
* Don't allocate single blocks, but alloc a contingent of this many
* blocks in one swoop. This must be a power of two.
*/
#ifndef TARGET_WASM
#define MS_BLOCK_ALLOC_NUM 32
#else
// WASM doesn't support partial munmap, so we can't free individual blocks
// we use posix_memalign and free the whole block at once
#define MS_BLOCK_ALLOC_NUM 1
#endif

#define MS_NUM_MARK_WORDS ((ms_block_size / SGEN_ALLOC_ALIGN + sizeof (guint32) * 8 - 1) / (sizeof (guint32) * 8))

Expand Down Expand Up @@ -2140,9 +2146,6 @@ major_free_swept_blocks (size_t section_reserve)
* a VirtualAlloc ()-ed block.
*/
return;
#elif defined(HOST_WASM)
if (!mono_opt_wasm_mmap)
return;
#endif

{
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ set(utils_arch_sources "${utils_arch_sources};mono-hwcap-riscv.c")
elseif(TARGET_S390X)
set(utils_arch_sources "${utils_arch_sources};mono-hwcap-s390x.c")
elseif(TARGET_WASM)
set(utils_arch_sources "${utils_arch_sources};mono-hwcap-wasm.c;mono-mmap-wasm.c;mono-wasm-pagemgr.c")
set(utils_arch_sources "${utils_arch_sources};mono-hwcap-wasm.c;mono-mmap-wasm.c")
elseif(TARGET_WASI)
set(utils_arch_sources "${utils_arch_sources};mono-hwcap-wasm.c")
elseif(TARGET_POWERPC OR TARGET_POWERPC64)
Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/utils/lock-free-alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ typedef struct {
} MonoLockFreeAllocator;

#ifdef HOST_WASM
#define LOCK_FREE_ALLOC_SB_MAX_SIZE (mono_opt_wasm_mmap ? 65536 : 16384)
#define LOCK_FREE_ALLOC_SB_MAX_SIZE 16384 * 32
#else
#define LOCK_FREE_ALLOC_SB_MAX_SIZE 16384
#endif
Expand Down
146 changes: 30 additions & 116 deletions src/mono/mono/utils/mono-mmap-wasm.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@
#include <mono/utils/atomic.h>
#include <mono/utils/options.h>

#include "mono-wasm-pagemgr.h"

#define BEGIN_CRITICAL_SECTION do { \
MonoThreadInfo *__info = mono_thread_info_current_unchecked (); \
if (__info) __info->inside_critical_region = TRUE; \
Expand All @@ -37,22 +35,7 @@
int
mono_pagesize (void)
{
if (mono_opt_wasm_mmap)
return MWPM_PAGE_SIZE;

static int saved_pagesize = 0;

if (saved_pagesize)
return saved_pagesize;

// Prefer sysconf () as it's signal safe.
#if defined (HAVE_SYSCONF) && defined (_SC_PAGESIZE)
saved_pagesize = sysconf (_SC_PAGESIZE);
#else
saved_pagesize = getpagesize ();
#endif

return saved_pagesize;
return 16384;
}

int
Expand Down Expand Up @@ -96,122 +79,50 @@ mono_setmmapjit (int flag)
/* Ignored on HOST_WASM */
}

static void*
valloc_impl (void *addr, size_t size, int flags, MonoMemAccountType type)
{
void *ptr;
int mflags = 0;
int prot = prot_from_flags (flags);

if (!mono_valloc_can_alloc (size))
return NULL;

if (size == 0)
/* emscripten throws an exception on 0 length */
return NULL;

mflags |= MAP_ANONYMOUS;
mflags |= MAP_PRIVATE;

BEGIN_CRITICAL_SECTION;
if (mono_opt_wasm_mmap) {
// FIXME: Make this work if the requested address range is free
if ((flags & MONO_MMAP_FIXED) && addr)
return NULL;

ptr = mwpm_alloc_range (size, (flags & MONO_MMAP_NOZERO) == 0);
if (!ptr)
return NULL;
} else
ptr = mmap (addr, size, prot, mflags, -1, 0);
END_CRITICAL_SECTION;

if (ptr == MAP_FAILED)
return NULL;

mono_account_mem (type, (ssize_t)size);

return ptr;
}

void*
mono_valloc (void *addr, size_t size, int flags, MonoMemAccountType type)
mono_valloc (void *addr, size_t length, int flags, MonoMemAccountType type)
{
#if HOST_WASI
// WASI implements mmap using malloc, so the returned address is not page aligned
// and our code depends on it
g_assert (!addr);
return mono_valloc_aligned (size, mono_pagesize (), flags, type);
#else
return valloc_impl (addr, size, flags, type);
#endif
g_assert (addr == NULL);
return mono_valloc_aligned (length, mono_pagesize (), flags, type);
}

static GHashTable *valloc_hash;

typedef struct {
void *addr;
int size;
} VallocInfo;

void*
mono_valloc_aligned (size_t size, size_t alignment, int flags, MonoMemAccountType type)
{
// We don't need padding if the alignment is compatible with the page size
if (mono_opt_wasm_mmap && ((MWPM_PAGE_SIZE % alignment) == 0))
return valloc_impl (NULL, size, flags, type);

/* Allocate twice the memory to be able to put the block on an aligned address */
char *mem = (char *) valloc_impl (NULL, size + alignment, flags, type);
char *aligned;
#ifdef DISABLE_THREADS
void *old_sbrk = NULL;
if ((flags & MONO_MMAP_NOZERO) == 0) {
old_sbrk = sbrk (0);
}
#endif

if (!mem)
void *res = NULL;
if (posix_memalign (&res, alignment, size))
return NULL;

aligned = mono_aligned_address (mem, size, alignment);
#ifdef DISABLE_THREADS
if ((flags & MONO_MMAP_NOZERO) == 0 && old_sbrk > res) {
// this means that we got an old block, not the new block from sbrk
memset (res, 0, size);
}
#else
if ((flags & MONO_MMAP_NOZERO) == 0) {
memset (res, 0, size);
}
#endif

/* The mmap implementation in emscripten cannot unmap parts of regions */
/* Free the other two parts in when 'aligned' is freed */
// FIXME: This doubles the memory usage
if (!valloc_hash)
valloc_hash = g_hash_table_new (NULL, NULL);
VallocInfo *info = g_new0 (VallocInfo, 1);
info->addr = mem;
info->size = size + alignment;
g_hash_table_insert (valloc_hash, aligned, info);
mono_account_mem (type, (ssize_t)size);

return aligned;
return res;
}

int
mono_vfree (void *addr, size_t length, MonoMemAccountType type)
{
VallocInfo *info = (VallocInfo*)(valloc_hash ? g_hash_table_lookup (valloc_hash, addr) : NULL);

if (info) {
/*
* We are passed the aligned address in the middle of the mapping allocated by
* mono_valloc_align (), free the original mapping.
*/
BEGIN_CRITICAL_SECTION;
if (mono_opt_wasm_mmap)
mwpm_free_range (info->addr, info->size);
else
munmap (info->addr, info->size);
END_CRITICAL_SECTION;
g_free (info);
g_hash_table_remove (valloc_hash, addr);
} else {
// FIXME: We could be trying to unmap part of an aligned mapping, in which case the
// hash lookup failed because addr isn't exactly the start of the mapping.
// Ideally if the custom page manager is enabled, we won't have done aligned alloc.
BEGIN_CRITICAL_SECTION;
if (mono_opt_wasm_mmap)
mwpm_free_range (addr, length);
else
munmap (addr, length);
END_CRITICAL_SECTION;
}
// NOTE: this doesn't implement partial freeing like munmap does
// we set MS_BLOCK_ALLOC_NUM to 1 to avoid partial freeing
g_free (addr);

mono_account_mem (type, -(ssize_t)length);

Expand Down Expand Up @@ -267,6 +178,9 @@ mono_file_unmap (void *addr, void *handle)
int
mono_mprotect (void *addr, size_t length, int flags)
{
if (flags & MONO_MMAP_DISCARD) {
memset (addr, 0, length);
}
return 0;
}

Expand Down
Loading

0 comments on commit a3fe47e

Please sign in to comment.