Skip to content

Commit

Permalink
feat: add example of early free for wasm binary buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
eloparco committed May 13, 2024
1 parent c18c0d7 commit af265e0
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 11 deletions.
5 changes: 3 additions & 2 deletions core/iwasm/common/wasm_c_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -2999,9 +2999,10 @@ wasm_module_get_name(wasm_module_t *module)
}

bool
wasm_module_is_underlying_binary_cloned(const wasm_module_t *module)
wasm_module_is_underlying_binary_freeable(const wasm_module_t *module)
{
return ((wasm_module_ex_t *)module)->is_binary_cloned;
return ((wasm_module_ex_t *)module)->is_binary_cloned
&& wasm_runtime_is_underlying_binary_freeable(*module);
}

static wasm_func_t *
Expand Down
17 changes: 15 additions & 2 deletions core/iwasm/common/wasm_runtime_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -1350,14 +1350,18 @@ wasm_runtime_load_ex(uint8 *buf, uint32 size, const LoadArgs *args,
true,
#endif
args, error_buf, error_buf_size);
((WASMModule *)module_common)->is_binary_freeable = true;
if (module_common)
((WASMModule *)module_common)->is_binary_freeable =
args->wasm_binary_freeable;
#endif
}
else if (get_package_type(buf, size) == Wasm_Module_AoT) {
#if WASM_ENABLE_AOT != 0
module_common = (WASMModuleCommon *)aot_load_from_aot_file(
buf, size, args, error_buf, error_buf_size);
((AOTModule *)module_common)->is_binary_freeable = true;
if (module_common)
((AOTModule *)module_common)->is_binary_freeable =
args->wasm_binary_freeable;
#endif
}
else {
Expand Down Expand Up @@ -1402,6 +1406,7 @@ wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot,
LOG_DEBUG("WASM module load failed from sections");
return NULL;
}
((WASMModule *)module_common)->is_binary_freeable = true;
return register_module_with_null_name(module_common, error_buf,
error_buf_size);
#endif
Expand All @@ -1414,6 +1419,7 @@ wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot,
LOG_DEBUG("WASM module load failed from sections");
return NULL;
}
((AOTModule *)module_common)->is_binary_freeable = true;
return register_module_with_null_name(module_common, error_buf,
error_buf_size);
#endif
Expand Down Expand Up @@ -7180,7 +7186,14 @@ wasm_runtime_is_underlying_binary_freeable(const wasm_module_t module)

#if WASM_ENABLE_INTERP != 0
if (module->module_type == Wasm_Module_Bytecode) {
#if (WASM_ENABLE_JIT != 0 || WASM_ENABLE_FAST_JIT != 0) \
&& (WASM_ENABLE_LAZY_JIT != 0)
is_freeable = false;
#elif WASM_ENABLE_FAST_INTERP == 0
is_freeable = false;
#else
is_freeable = ((WASMModule *)module)->is_binary_freeable;
#endif
}
#endif
#if WASM_ENABLE_AOT != 0
Expand Down
2 changes: 1 addition & 1 deletion core/iwasm/include/wasm_c_api.h
Original file line number Diff line number Diff line change
Expand Up @@ -562,7 +562,7 @@ WASM_API_EXTERN void wasm_shared_module_delete(own wasm_shared_module_t*);
WASM_API_EXTERN bool wasm_module_set_name(wasm_module_t*, const char* name);
WASM_API_EXTERN const char *wasm_module_get_name(wasm_module_t*);

WASM_API_EXTERN bool wasm_module_is_underlying_binary_cloned(const wasm_module_t* module);
WASM_API_EXTERN bool wasm_module_is_underlying_binary_freeable(const wasm_module_t* module);


// Function Instances
Expand Down
11 changes: 6 additions & 5 deletions core/iwasm/interpreter/wasm_mini_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -3192,8 +3192,8 @@ static union {
#define is_little_endian() (__ue.b == 1)

static bool
load(const uint8 *buf, uint32 size, WASMModule *module, char *error_buf,
uint32 error_buf_size)
load(const uint8 *buf, uint32 size, WASMModule *module,
bool wasm_binary_freeable, char *error_buf, uint32 error_buf_size)
{
const uint8 *buf_end = buf + size;
const uint8 *p = buf, *p_end = buf_end;
Expand All @@ -3218,8 +3218,8 @@ load(const uint8 *buf, uint32 size, WASMModule *module, char *error_buf,
}

if (!create_sections(buf, size, &section_list, error_buf, error_buf_size)
|| !load_from_sections(module, section_list, true, error_buf,
error_buf_size)) {
|| !load_from_sections(module, section_list, !wasm_binary_freeable,
error_buf, error_buf_size)) {
destroy_sections(section_list);
return false;
}
Expand All @@ -3244,7 +3244,8 @@ wasm_loader_load(uint8 *buf, uint32 size, const LoadArgs *args, char *error_buf,
module->load_size = size;
#endif

if (!load(buf, size, module, error_buf, error_buf_size)) {
if (!load(buf, size, module, args->wasm_binary_freeable, error_buf,
error_buf_size)) {
goto fail;
}

Expand Down
2 changes: 1 addition & 1 deletion doc/memory_tune.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,5 @@ Normally there are some methods to tune the memory usage:
- set the app heap size with `wasm_runtime_instantiate`
- use `nostdlib` mode, add `-Wl,--strip-all`: refer to [How to reduce the footprint](./build_wasm_app.md#2-how-to-reduce-the-footprint) of building wasm app for more details
- use XIP mode, refer to [WAMR XIP (Execution In Place) feature introduction](./xip.md) for more details
- when using the Wasm C API in fast interpreter or AOT mode, set `clone_wasm_binary=false` in `LoadArgs` and free the wasm binary buffer (with `wasm_byte_vec_delete`) after module loading; `wasm_runtime_is_underlying_binary_freeable` can be queried to check if the wasm binary buffer can be safely freed
- when using the Wasm C API in fast interpreter or AOT mode, set `clone_wasm_binary=false` in `LoadArgs` and free the wasm binary buffer (with `wasm_byte_vec_delete`) after module loading; `wasm_module_is_underlying_binary_freeable` can be queried to check if the wasm binary buffer can be safely freed (see [the example](../samples/basic/src/free_buffer_early.c))
- when using the wasm/AOT loader in fast interpreter or AOT mode, set `wasm_binary_freeable=true` in `LoadArgs` and free the wasm binary buffer (with `wasm_byte_vec_delete`) after module loading; `wasm_runtime_is_underlying_binary_freeable` can be queried to check if the wasm binary buffer can be safely freed
4 changes: 4 additions & 0 deletions samples/basic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -79,12 +79,16 @@ include_directories(${CMAKE_CURRENT_LIST_DIR}/src)
include (${SHARED_DIR}/utils/uncommon/shared_uncommon.cmake)

add_executable (basic src/main.c src/native_impl.c ${UNCOMMON_SHARED_SOURCE})
add_executable (free_buffer_early src/free_buffer_early.c ${UNCOMMON_SHARED_SOURCE})

check_pie_supported()
set_target_properties (basic PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties (free_buffer_early PROPERTIES POSITION_INDEPENDENT_CODE ON)

if (APPLE)
target_link_libraries (basic vmlib -lm -ldl -lpthread)
target_link_libraries (free_buffer_early vmlib -lm -ldl -lpthread)
else ()
target_link_libraries (basic vmlib -lm -ldl -lpthread -lrt)
target_link_libraries (free_buffer_early vmlib -lm -ldl -lpthread -lrt)
endif ()
1 change: 1 addition & 0 deletions samples/basic/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ OUT_FILE=${i%.*}.wasm
-Wl,--export=generate_float \
-Wl,--export=float_to_string \
-Wl,--export=calculate\
-Wl,--export=mul7\
-Wl,--allow-undefined \
-o ${OUT_DIR}/wasm-apps/${OUT_FILE} ${APP_SRC}

Expand Down
121 changes: 121 additions & 0 deletions samples/basic/src/free_buffer_early.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright (C) 2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/

#include "wasm_export.h"
#include "bh_read_file.h"

void
my_log(uint32 log_level, const char *file, int line, const char *fmt, ...)
{
char buf[200];
snprintf(buf, sizeof(buf), "[WamrLogger] %s", fmt);

va_list ap;
va_start(ap, fmt);
vprintf(buf, ap);
va_end(ap);
}

int
my_vprintf(const char *format, va_list ap)
{
return vprintf(format, ap);
}

void
print_usage(void)
{
fprintf(stdout, "Options:\r\n");
fprintf(stdout, " -f [path of wasm file] \n");
}

int
main(int argc, char *argv_main[])
{
static char global_heap_buf[512 * 1024];
char *buffer = NULL, error_buf[128];
int opt;
char *wasm_path = NULL;
bool success;

wasm_module_t module = NULL;
wasm_module_inst_t module_inst = NULL;
uint32 buf_size, stack_size = 8092, heap_size = 8092;
LoadArgs load_args = { 0 };

RuntimeInitArgs init_args;
memset(&init_args, 0, sizeof(RuntimeInitArgs));

while ((opt = getopt(argc, argv_main, "hf:")) != -1) {
switch (opt) {
case 'f':
wasm_path = optarg;
break;
case 'h':
print_usage();
return 0;
case '?':
print_usage();
return 0;
}
}
if (optind == 1) {
print_usage();
return 0;
}

init_args.mem_alloc_type = Alloc_With_Pool;
init_args.mem_alloc_option.pool.heap_buf = global_heap_buf;
init_args.mem_alloc_option.pool.heap_size = sizeof(global_heap_buf);

if (!wasm_runtime_full_init(&init_args)) {
printf("Init runtime environment failed.\n");
return -1;
}

buffer = bh_read_file_to_buffer(wasm_path, &buf_size);
if (!buffer) {
printf("Open wasm app file [%s] failed.\n", wasm_path);
goto fail;
}

load_args.wasm_binary_freeable = true;
module = wasm_runtime_load_ex((uint8 *)buffer, buf_size, &load_args,
error_buf, sizeof(error_buf));
if (!module) {
printf("Load wasm module failed. error: %s\n", error_buf);
goto fail;
}

if (wasm_runtime_is_underlying_binary_freeable(module)) {
printf("Able to free wasm binary buffer.\n");
wasm_runtime_free(buffer);
buffer = NULL;
}

module_inst = wasm_runtime_instantiate(module, stack_size, heap_size,
error_buf, sizeof(error_buf));
if (!module_inst) {
printf("Instantiate wasm module failed. error: %s.\n", error_buf);
goto fail;
}

char *args[1] = { "3" };
success = wasm_application_execute_func(module_inst, "mul7", 1, args);
if (!success) {
printf("Unable to execute function.\n");
goto fail;
}

fail:
if (module_inst)
wasm_runtime_deinstantiate(module_inst);
if (module)
wasm_runtime_unload(module);
if (buffer)
wasm_runtime_free(buffer);
wasm_runtime_destroy();
return 0;
}

0 comments on commit af265e0

Please sign in to comment.