Skip to content

User defined memory allocator for different purposes #3316

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

Merged

Conversation

dongsheng28849455
Copy link
Contributor

Some issues that 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.

@wenyongh
Copy link
Contributor

@dongsheng28849455 the code adds control for the behavior of both wasm_runtime_malloc and wasm_memory_enlarge, but they are not so relevant, using a flag to control them may make the source code a little strange. I guess in your application the os_mmap uses the same allocator as the allocator of wasm_runtime_malloc, but it seems you just want to control the allocation of linear memory, so is it better to redirect os_mmap to use other allocator? Or add a flag for os_mmap?

@dongsheng28849455
Copy link
Contributor Author

hi, @wenyongh,
I used to want to modify it in os_mmap, but from the semantics of os_mmap, it seems more suitable for scenarios that require mapping virtual memory and setting properties such as rwx for it. For the allocation that only applies to linear memory, the only available attributes currently are map_prot and map_flags, which are difficult to correspond to the purpose of memory unless a new attribute type is added.

In our current application scenario, we hope to further customize memory allocators, distinguishing between linear memory and regular runtime managed memory. Compared to os_mmp with more abstraction, a customized memory allocator seems more suitable for this user specific usage scenario.

@@ -554,3 +554,6 @@ else ()
# Disable aot intrinsics for interp, fast-jit and llvm-jit
add_definitions (-DWASM_ENABLE_AOT_INTRINSICS=0)
endif ()
if (WAMR_BUILD_MEM_ALLOC_WITH_USAGE EQUAL 1)
Copy link
Contributor

Choose a reason for hiding this comment

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

There is already a cmake variable WAMR_BUILD_ALLOC_WITH_USER_DATA, here how about using WAMR_BUILD_ALLOC_WITH_USAGE and putting these lines together with WAMR_BUILD_ALLOC_WITH_USER_DATA?

And it seems only non shared memory is supported since the full_size_mmaped isn't handled in wasm_enlarge_memory_internal, how about adding a check here, e.g. report error if WAMR_BUILD_SHARED_MEMORY is defined.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

There is already a cmake variable WAMR_BUILD_ALLOC_WITH_USER_DATA, here how about using WAMR_BUILD_ALLOC_WITH_USAGE and putting these lines together with WAMR_BUILD_ALLOC_WITH_USER_DATA?

I'd like reuse WAMR_BUILD_ALLOC_WITH_USAGE, but that seems will change the API signiture of:
static void *(*malloc_func)(void *user_data, unsigned int size) = NULL;
that will impact its user.
BTW, the user defined malloc_func, realloc_func and free_func seems only have a hidden convention with its user, can we make it more abstract and explicitly declared in wamr_export.h? then we can include all of these things in general API.

Copy link
Contributor

Choose a reason for hiding this comment

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

Adding WAMR_BUILD_ALLOC_WITH_USAGE is good (together with WAMR_BUILD_ALLOC_WITH_USER_DATA) to me, but since developer can just use wasm_export.h and libvmlib.a or libiwasm.so for his project, normally we should not add macro control in wasm_export.h, it is not easy to declare function prototypes for malloc_func/free_func, how about we just add comments about the prototypes in:

void *malloc_func;
void *realloc_func;
void *free_func;

Copy link
Contributor

Choose a reason for hiding this comment

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

And if that, we had better update build_wamr.doc about the two cmake flags, and control the code like:

static void *(*malloc_func)(
#if WASM_MEM_ALLOC_WITH_USAGE
mem_alloc_usage_t usage,
#endif
#if WASM_MEM_ALLOC_WITH_USER_DATA
void *user_data,
#endif
unsigned int size) = NULL;

Copy link
Contributor Author

Choose a reason for hiding this comment

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

what about this in wamr_export.h:

typedef enum {
    Alloc_For_Runtime,
    Alloc_For_LinearMemory
} mem_alloc_usage_t;

typedef struct {
    mem_alloc_usage_t usage;
    void *user_data;
} user_data_t;

typedef void* (*malloc_func_t)(const user_data_t *data, uint64_t size);
typedef void* (*realloc_func_t)(const user_data_t *data, void *ptr, uint64_t size);
typedef void* (*free_func_t)(const user_data_t *data, void *ptr);

and in wasm_memory.c

static void *allocator_user_data = NULL;
static malloc_func_t malloc_func = NULL;
static realloc_func_t realloc_func = NULL;
static free_func_t free_func = NULL;
...
static bool
wasm_memory_init_with_allocator(malloc_func_t malloc_func_ptr, realloc_func_t realloc_func_ptr,
                                free_func_t free_func_ptr)
{
    if (malloc_func_ptr && free_func_ptr && malloc_func_ptr != free_func_ptr) {
        memory_mode = MEMORY_MODE_ALLOCATOR;
        malloc_func = malloc_func_ptr;
        realloc_func = realloc_func_ptr;
        free_func = free_func_ptr;
        return true;
    }
    LOG_ERROR("Init memory with allocator (%p, %p, %p) failed.\n",
              malloc_func_ptr, realloc_func_ptr, free_func_ptr);
    return false;
}

then we can merge WASM_MEM_ALLOC_WITH_USAGE&WASM_MEM_ALLOC_WITH_USER_DATA together.

Copy link
Contributor

Choose a reason for hiding this comment

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

My preference is we had better not change the signature of malloc_func/realloc_func functions for general scenarios, they have been used by many developers, changing them will cause many inconvenient.

ret = false;
goto return_func;
}
memory->heap_data = memory_data_new + (heap_data_old - memory_data_old);
Copy link
Contributor

Choose a reason for hiding this comment

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

The heap data (base address) may be changed, should call mem_allocator_migrate for it like below code since the internal pointers (absolute addresses) inside the heap should be updated, or they will point to invalid buffer. If not, allocation by wasm app or module_malloc by host may fail.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

OK

Comment on lines +132 to +133
if (CONFIG_INTERPRETERS_WAMR_MEM_ALLOC_WITH_USAGE)
set(WAMR_BUILD_MEM_ALLOC_WITH_USAGE 1)
Copy link
Contributor

Choose a reason for hiding this comment

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

How about CONFIG_INTERPRETERS_WAMR_ALLOC_WITH_USAGE and WAMR_BUILD_ALLOC_WITH_USAGE?

@wenyongh
Copy link
Contributor

hi, @wenyongh, I used to want to modify it in os_mmap, but from the semantics of os_mmap, it seems more suitable for scenarios that require mapping virtual memory and setting properties such as rwx for it. For the allocation that only applies to linear memory, the only available attributes currently are map_prot and map_flags, which are difficult to correspond to the purpose of memory unless a new attribute type is added.

In our current application scenario, we hope to further customize memory allocators, distinguishing between linear memory and regular runtime managed memory. Compared to os_mmp with more abstraction, a customized memory allocator seems more suitable for this user specific usage scenario.

OK, a concern is that the aot code and some aot data sections are also allocated by os_mmap, will they cause memory fragmentation?

@dongsheng28849455
Copy link
Contributor Author

dongsheng28849455 commented Apr 16, 2024

OK, a concern is that the aot code and some aot data sections are also allocated by os_mmap, will they cause memory fragmentation?

The feature's purpose is not to eliminate the memory fragmentation, it's focus on processing linear memory separately from system normal heap. so as reduce the probability of being unable to allocate in the pool when fragmentation exists.

@wenyongh
Copy link
Contributor

OK, a concern is that the aot code and some aot data sections are also allocated by os_mmap, will they cause memory fragmentation?

The feature's purpose is not to eliminate the memory fragmentation, it's focus on processing linear memory separately from system normal heap. so as reduce the probability of being unable to allocate in the pool when fragmentation exists.

OK, thanks.

1, WAMR_BUILD_MEM_ALLOC_WITH_USAGE -> WAMR_BUILD_ALLOC_WITH_USAGE
2, redefine the malloc, free, realloc signature.
3, let customer handle full_size_mmaped also in its realloc.
4, update the doc
if (!(memory_data_new =
realloc_func(Alloc_For_LinearMemory, full_size_mmaped,
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
NULL,
Copy link
Contributor

Choose a reason for hiding this comment

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

Had better use allocator_user_data?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

when we handling the linear memory, this paremter is not used here, NULL just for passing build

Copy link
Contributor

Choose a reason for hiding this comment

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

OK, thanks.

(void)map_size;
free_func(Alloc_For_LinearMemory,
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
NULL,
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above.

Copy link
Contributor

@wenyongh wenyongh left a comment

Choose a reason for hiding this comment

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

LGTM

if (!(memory_data_new =
realloc_func(Alloc_For_LinearMemory, full_size_mmaped,
#if WASM_MEM_ALLOC_WITH_USER_DATA != 0
NULL,
Copy link
Contributor

Choose a reason for hiding this comment

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

OK, thanks.

Copy link
Contributor Author

@dongsheng28849455 dongsheng28849455 left a comment

Choose a reason for hiding this comment

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

LGTM

@wenyongh wenyongh merged commit ba59e56 into bytecodealliance:main Apr 18, 2024
@no1wudi
Copy link
Collaborator

no1wudi commented Apr 18, 2024

@dongsheng28849455 Could add essential document to docs instead leave them in commit message? It's not easy for end user to fetch these informations.

@dongsheng28849455
Copy link
Contributor Author

@dongsheng28849455 Could add essential document to docs instead leave them in commit message? It's not easy for end user to fetch these informations.

good point, I have added some info in the doc:
user-defined-linear-memory-allocator

vickiegpt pushed a commit to vickiegpt/wamr-aot-gc-checkpoint-restore that referenced this pull request May 1, 2024
…e#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.
vickiegpt pushed a commit to vickiegpt/wamr-aot-gc-checkpoint-restore that referenced this pull request May 2, 2024
…e#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.

Signed-off-by: victoryang00 <[email protected]>
vickiegpt pushed a commit to vickiegpt/wamr-aot-gc-checkpoint-restore that referenced this pull request May 27, 2024
…e#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.
vickiegpt pushed a commit to vickiegpt/wamr-aot-gc-checkpoint-restore that referenced this pull request May 27, 2024
…e#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.

Signed-off-by: victoryang00 <[email protected]>
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

Successfully merging this pull request may close these issues.

4 participants