User defined memory allocator for different purposes (#3316)

Some issues are related with memory fragmentation, which may cause
the linear memory cannot be allocated. In WAMR, the memory managed
by the system is often trivial, but linear memory usually directly allocates
a large block and often remains unchanged for a long time. Their sensitivity
and contribution to fragmentation are different, which is suitable for
different allocation strategies. If we can control the linear memory's allocation,
do not make it from system heap, the overhead of heap management might
be avoided.

Add `mem_alloc_usage_t usage` as the first argument for user defined
malloc/realloc/free functions when `WAMR_BUILD_ALLOC_WITH_USAGE` cmake
variable is set as 1, and make passing `Alloc_For_LinearMemory` to the
argument when allocating the linear memory.
This commit is contained in:
dongsheng28849455 2024-04-18 19:40:57 +08:00 committed by GitHub
parent 68bd30c6f9
commit ba59e56e19
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 131 additions and 20 deletions

View File

@ -556,6 +556,9 @@ else ()
# Disable aot intrinsics for interp, fast-jit and llvm-jit # Disable aot intrinsics for interp, fast-jit and llvm-jit
add_definitions (-DWASM_ENABLE_AOT_INTRINSICS=0) add_definitions (-DWASM_ENABLE_AOT_INTRINSICS=0)
endif () endif ()
if (WAMR_BUILD_ALLOC_WITH_USAGE EQUAL 1)
add_definitions(-DWASM_MEM_ALLOC_WITH_USAGE=1)
endif()
if (NOT WAMR_BUILD_SANITIZER STREQUAL "") if (NOT WAMR_BUILD_SANITIZER STREQUAL "")
message (" Sanitizer ${WAMR_BUILD_SANITIZER} enabled") message (" Sanitizer ${WAMR_BUILD_SANITIZER} enabled")
endif () endif ()

View File

@ -587,4 +587,8 @@
#define WASM_TABLE_MAX_SIZE 1024 #define WASM_TABLE_MAX_SIZE 1024
#endif #endif
#ifndef WASM_MEM_ALLOC_WITH_USAGE
#define WASM_MEM_ALLOC_WITH_USAGE 0
#endif
#endif /* end of _CONFIG_H_ */ #endif /* end of _CONFIG_H_ */

View File

@ -29,16 +29,35 @@ static void *enlarge_memory_error_user_data;
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 #if WASM_MEM_ALLOC_WITH_USER_DATA != 0
static void *allocator_user_data = NULL; static void *allocator_user_data = NULL;
static void *(*malloc_func)(void *user_data, unsigned int size) = NULL;
static void *(*realloc_func)(void *user_data, void *ptr,
unsigned int size) = NULL;
static void (*free_func)(void *user_data, void *ptr) = NULL;
#else
static void *(*malloc_func)(unsigned int size) = NULL;
static void *(*realloc_func)(void *ptr, unsigned int size) = NULL;
static void (*free_func)(void *ptr) = NULL;
#endif #endif
static void *(*malloc_func)(
#if WASM_MEM_ALLOC_WITH_USAGE != 0
mem_alloc_usage_t usage,
#endif
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
void *user_data,
#endif
unsigned int size) = NULL;
static void *(*realloc_func)(
#if WASM_MEM_ALLOC_WITH_USAGE != 0
mem_alloc_usage_t usage, bool full_size_mmaped,
#endif
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
void *user_data,
#endif
void *ptr, unsigned int size) = NULL;
static void (*free_func)(
#if WASM_MEM_ALLOC_WITH_USAGE != 0
mem_alloc_usage_t usage,
#endif
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
void *user_data,
#endif
void *ptr) = NULL;
static unsigned int global_pool_size; static unsigned int global_pool_size;
static uint64 static uint64
@ -177,11 +196,14 @@ wasm_runtime_malloc_internal(unsigned int size)
return mem_allocator_malloc(pool_allocator, size); return mem_allocator_malloc(pool_allocator, size);
} }
else if (memory_mode == MEMORY_MODE_ALLOCATOR) { else if (memory_mode == MEMORY_MODE_ALLOCATOR) {
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 return malloc_func(
return malloc_func(allocator_user_data, size); #if WASM_MEM_ALLOC_WITH_USAGE != 0
#else Alloc_For_Runtime,
return malloc_func(size);
#endif #endif
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
allocator_user_data,
#endif
size);
} }
else { else {
return os_malloc(size); return os_malloc(size);
@ -201,11 +223,14 @@ wasm_runtime_realloc_internal(void *ptr, unsigned int size)
} }
else if (memory_mode == MEMORY_MODE_ALLOCATOR) { else if (memory_mode == MEMORY_MODE_ALLOCATOR) {
if (realloc_func) if (realloc_func)
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 return realloc_func(
return realloc_func(allocator_user_data, ptr, size); #if WASM_MEM_ALLOC_WITH_USAGE != 0
#else Alloc_For_Runtime, false,
return realloc_func(ptr, size);
#endif #endif
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
allocator_user_data,
#endif
ptr, size);
else else
return NULL; return NULL;
} }
@ -233,11 +258,14 @@ wasm_runtime_free_internal(void *ptr)
mem_allocator_free(pool_allocator, ptr); mem_allocator_free(pool_allocator, ptr);
} }
else if (memory_mode == MEMORY_MODE_ALLOCATOR) { else if (memory_mode == MEMORY_MODE_ALLOCATOR) {
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 free_func(
free_func(allocator_user_data, ptr); #if WASM_MEM_ALLOC_WITH_USAGE != 0
#else Alloc_For_Runtime,
free_func(ptr);
#endif #endif
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
allocator_user_data,
#endif
ptr);
} }
else { else {
os_free(ptr); os_free(ptr);
@ -765,6 +793,29 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count)
bh_assert(total_size_new bh_assert(total_size_new
<= GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64)); <= GET_MAX_LINEAR_MEMORY_SIZE(memory->is_memory64));
#if WASM_MEM_ALLOC_WITH_USAGE != 0
if (!(memory_data_new =
realloc_func(Alloc_For_LinearMemory, full_size_mmaped,
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
NULL,
#endif
memory_data_old, total_size_new))) {
ret = false;
goto return_func;
}
if (heap_size > 0) {
if (mem_allocator_migrate(memory->heap_handle,
(char *)heap_data_old
+ (memory_data_new - memory_data_old),
heap_size)
!= 0) {
ret = false;
}
}
memory->heap_data = memory_data_new + (heap_data_old - memory_data_old);
memory->heap_data_end = memory->heap_data + heap_size;
memory->memory_data = memory_data_new;
#else
if (full_size_mmaped) { if (full_size_mmaped) {
#ifdef BH_PLATFORM_WINDOWS #ifdef BH_PLATFORM_WINDOWS
if (!os_mem_commit(memory->memory_data_end, if (!os_mem_commit(memory->memory_data_end,
@ -823,6 +874,7 @@ wasm_enlarge_memory_internal(WASMModuleInstance *module, uint32 inc_page_count)
os_writegsbase(memory_data_new); os_writegsbase(memory_data_new);
#endif #endif
} }
#endif /* end of WASM_MEM_ALLOC_WITH_USAGE */
memory->num_bytes_per_page = num_bytes_per_page; memory->num_bytes_per_page = num_bytes_per_page;
memory->cur_page_count = total_page_count; memory->cur_page_count = total_page_count;
@ -903,8 +955,19 @@ wasm_deallocate_linear_memory(WASMMemoryInstance *memory_inst)
#else #else
map_size = 8 * (uint64)BH_GB; map_size = 8 * (uint64)BH_GB;
#endif #endif
#if WASM_MEM_ALLOC_WITH_USAGE != 0
(void)map_size;
free_func(Alloc_For_LinearMemory,
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
NULL,
#endif
memory_inst->memory_data);
#else
wasm_munmap_linear_memory(memory_inst->memory_data, wasm_munmap_linear_memory(memory_inst->memory_data,
memory_inst->memory_data_size, map_size); memory_inst->memory_data_size, map_size);
#endif
memory_inst->memory_data = NULL; memory_inst->memory_data = NULL;
} }
@ -954,9 +1017,20 @@ wasm_allocate_linear_memory(uint8 **data, bool is_shared_memory,
*memory_data_size = align_as_and_cast(*memory_data_size, page_size); *memory_data_size = align_as_and_cast(*memory_data_size, page_size);
if (map_size > 0) { if (map_size > 0) {
#if WASM_MEM_ALLOC_WITH_USAGE != 0
(void)wasm_mmap_linear_memory;
if (!(*data = malloc_func(Alloc_For_LinearMemory,
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
NULL,
#endif
*memory_data_size))) {
return BHT_ERROR;
}
#else
if (!(*data = wasm_mmap_linear_memory(map_size, *memory_data_size))) { if (!(*data = wasm_mmap_linear_memory(map_size, *memory_data_size))) {
return BHT_ERROR; return BHT_ERROR;
} }
#endif
} }
return BHT_OK; return BHT_OK;

View File

@ -113,6 +113,11 @@ typedef enum {
Alloc_With_System_Allocator, Alloc_With_System_Allocator,
} mem_alloc_type_t; } mem_alloc_type_t;
typedef enum {
Alloc_For_Runtime,
Alloc_For_LinearMemory
} mem_alloc_usage_t;
/* Memory allocator option */ /* Memory allocator option */
typedef union MemAllocOption { typedef union MemAllocOption {
struct { struct {
@ -120,6 +125,9 @@ typedef union MemAllocOption {
uint32_t heap_size; uint32_t heap_size;
} pool; } pool;
struct { struct {
/* the function signature is varied when
WASM_MEM_ALLOC_WITH_USER_DATA and
WASM_MEM_ALLOC_WITH_USAGE are defined */
void *malloc_func; void *malloc_func;
void *realloc_func; void *realloc_func;
void *free_func; void *free_func;

View File

@ -254,6 +254,10 @@ Currently we only profile the memory consumption of module, module_instance and
> See [Enable segue optimization for wamrc when generating the aot file](./perf_tune.md#3-enable-segue-optimization-for-wamrc-when-generating-the-aot-file) for more details. > See [Enable segue optimization for wamrc when generating the aot file](./perf_tune.md#3-enable-segue-optimization-for-wamrc-when-generating-the-aot-file) for more details.
#### **User defined linear memory allocator**
- **WAMR_BUILD_ALLOC_WITH_USAGE**=1/0, default to disable if not set
> Notes: by default, the linear memory is allocated by system. when it's set to 1 and Alloc_With_Allocator is selected, it will be allocated by customer.
#### **Enable running PGO(Profile-Guided Optimization) instrumented AOT file** #### **Enable running PGO(Profile-Guided Optimization) instrumented AOT file**
- **WAMR_BUILD_STATIC_PGO**=1/0, default to disable if not set - **WAMR_BUILD_STATIC_PGO**=1/0, default to disable if not set
> Note: See [Use the AOT static PGO method](./perf_tune.md#5-use-the-aot-static-pgo-method) for more details. > Note: See [Use the AOT static PGO method](./perf_tune.md#5-use-the-aot-static-pgo-method) for more details.

View File

@ -129,6 +129,10 @@ if(CONFIG_INTERPRETERS_WAMR_GLOBAL_HEAP_POOL)
set(WAMR_BUILD_GLOBAL_HEAP_SIZE ${_HEAP_SIZE_}) set(WAMR_BUILD_GLOBAL_HEAP_SIZE ${_HEAP_SIZE_})
endif() endif()
if (CONFIG_INTERPRETERS_WAMR_MEM_ALLOC_WITH_USAGE)
set(WAMR_BUILD_MEM_ALLOC_WITH_USAGE 1)
endif()
if(CONFIG_INTERPRETERS_WAMR_ENABLE_SPEC_TEST) if(CONFIG_INTERPRETERS_WAMR_ENABLE_SPEC_TEST)
set(WAMR_BUILD_SPEC_TEST 1) set(WAMR_BUILD_SPEC_TEST 1)
endif() endif()

View File

@ -373,6 +373,11 @@ CFLAGS += -DWASM_ENABLE_GLOBAL_HEAP_POOL=1
CFLAGS += -DWASM_GLOBAL_HEAP_SIZE="$(CONFIG_INTERPRETERS_WAMR_GLOBAL_HEAP_POOL_SIZE) * 1024" CFLAGS += -DWASM_GLOBAL_HEAP_SIZE="$(CONFIG_INTERPRETERS_WAMR_GLOBAL_HEAP_POOL_SIZE) * 1024"
else else
CFLAGS += -DWASM_ENABLE_GLOBAL_HEAP_POOL=0 CFLAGS += -DWASM_ENABLE_GLOBAL_HEAP_POOL=0
ifeq ($(CONFIG_INTERPRETERS_WAMR_MEM_ALLOC_WITH_USAGE),y)
CFLAGS += -DWASM_MEM_ALLOC_WITH_USAGE=1
else
CFLAGS += -DWASM_MEM_ALLOC_WITH_USAGE=0
endif
endif endif
ifeq ($(CONFIG_INTERPRETERS_WAMR_ENABLE_SPEC_TEST),y) ifeq ($(CONFIG_INTERPRETERS_WAMR_ENABLE_SPEC_TEST),y)

View File

@ -445,6 +445,9 @@ static char global_heap_buf[WASM_GLOBAL_HEAP_SIZE] = { 0 };
#else #else
static void * static void *
malloc_func( malloc_func(
#if WASM_MEM_ALLOC_WITH_USAGE != 0
mem_alloc_usage_t usage,
#endif
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 #if WASM_MEM_ALLOC_WITH_USER_DATA != 0
void *user_data, void *user_data,
#endif #endif
@ -455,6 +458,9 @@ malloc_func(
static void * static void *
realloc_func( realloc_func(
#if WASM_MEM_ALLOC_WITH_USAGE != 0
mem_alloc_usage_t usage, bool full_size_mmaped,
#endif
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 #if WASM_MEM_ALLOC_WITH_USER_DATA != 0
void *user_data, void *user_data,
#endif #endif
@ -465,6 +471,9 @@ realloc_func(
static void static void
free_func( free_func(
#if WASM_MEM_ALLOC_WITH_USAGE != 0
mem_alloc_usage_t usage,
#endif
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0 #if WASM_MEM_ALLOC_WITH_USER_DATA != 0
void *user_data, void *user_data,
#endif #endif