introduce WAMR memory profiling tool (experimental) (#390)

This commit is contained in:
Xu Jun
2020-09-18 18:04:56 +08:00
committed by GitHub
parent 04a7cc322f
commit 0226dbbb3d
27 changed files with 848 additions and 205 deletions

View File

@ -43,6 +43,10 @@ wasm_exec_env_create_internal(struct WASMModuleInstanceCommon *module_inst,
exec_env->wasm_stack.s.top_boundary =
exec_env->wasm_stack.s.bottom + stack_size;
exec_env->wasm_stack.s.top = exec_env->wasm_stack.s.bottom;
#if WASM_ENABLE_MEMORY_TRACING != 0
wasm_runtime_dump_exec_env_mem_consumption(exec_env);
#endif
return exec_env;
#if WASM_ENABLE_THREAD_MGR != 0

View File

@ -92,7 +92,7 @@ typedef struct WASMExecEnv {
/* The native thread handle of current thread */
korp_tid handle;
#if WASM_ENABLE_INTERP != 0
#if WASM_ENABLE_INTERP != 0 && WASM_ENABLE_FAST_INTERP == 0
BlockAddr block_addr_cache[BLOCK_ADDR_CACHE_SIZE][BLOCK_ADDR_CONFLICT_SIZE];
#endif
@ -100,6 +100,10 @@ typedef struct WASMExecEnv {
WASMJmpBuf *jmpbuf_stack_top;
#endif
#if WASM_ENABLE_MEMORY_PROFILING != 0
uint32 max_wasm_stack_used;
#endif
/* The WASM stack size */
uint32 wasm_stack_size;
@ -154,13 +158,19 @@ wasm_exec_env_alloc_wasm_frame(WASMExecEnv *exec_env, unsigned size)
multiplying by 2 is enough. */
if (addr + size * 2 > exec_env->wasm_stack.s.top_boundary) {
/* WASM stack overflow. */
/* When throwing SOE, the preserved space must be enough. */
/* bh_assert(!exec_env->throwing_soe);*/
return NULL;
}
exec_env->wasm_stack.s.top += size;
#if WASM_ENABLE_MEMORY_PROFILING != 0
{
uint32 wasm_stack_used = exec_env->wasm_stack.s.top
- exec_env->wasm_stack.s.bottom;
if (wasm_stack_used > exec_env->max_wasm_stack_used)
exec_env->max_wasm_stack_used = wasm_stack_used;
}
#endif
return addr;
}

View File

@ -32,8 +32,6 @@ static memory_profile_t *memory_profiles_list = NULL;
static korp_mutex profile_lock;
#endif /* end of BH_ENABLE_MEMORY_PROFILING */
#ifndef MALLOC_MEMORY_FROM_SYSTEM
typedef enum Memory_Mode {
MEMORY_MODE_UNKNOWN = 0,
MEMORY_MODE_POOL,
@ -125,28 +123,32 @@ wasm_runtime_memory_pool_size()
return 1 * BH_GB;
}
void *
wasm_runtime_malloc(unsigned int size)
static inline void *
wasm_runtime_malloc_internal(unsigned int size)
{
if (memory_mode == MEMORY_MODE_UNKNOWN) {
LOG_WARNING("wasm_runtime_malloc failed: memory hasn't been initialize.\n");
return NULL;
} else if (memory_mode == MEMORY_MODE_POOL) {
}
else if (memory_mode == MEMORY_MODE_POOL) {
return mem_allocator_malloc(pool_allocator, size);
} else {
}
else {
return malloc_func(size);
}
}
void *
wasm_runtime_realloc(void *ptr, unsigned int size)
static inline void *
wasm_runtime_realloc_internal(void *ptr, unsigned int size)
{
if (memory_mode == MEMORY_MODE_UNKNOWN) {
LOG_WARNING("wasm_runtime_realloc failed: memory hasn't been initialize.\n");
return NULL;
} else if (memory_mode == MEMORY_MODE_POOL) {
}
else if (memory_mode == MEMORY_MODE_POOL) {
return mem_allocator_realloc(pool_allocator, ptr, size);
} else {
}
else {
if (realloc_func)
return realloc_func(ptr, size);
else
@ -154,20 +156,97 @@ wasm_runtime_realloc(void *ptr, unsigned int size)
}
}
void
wasm_runtime_free(void *ptr)
static inline void
wasm_runtime_free_internal(void *ptr)
{
if (memory_mode == MEMORY_MODE_UNKNOWN) {
LOG_WARNING("wasm_runtime_free failed: memory hasn't been initialize.\n");
} else if (memory_mode == MEMORY_MODE_POOL) {
}
else if (memory_mode == MEMORY_MODE_POOL) {
mem_allocator_free(pool_allocator, ptr);
} else {
}
else {
free_func(ptr);
}
}
#if BH_ENABLE_MEMORY_PROFILING != 0
void *
wasm_runtime_malloc(unsigned int size)
{
return wasm_runtime_malloc_internal(size);
}
void *
wasm_runtime_realloc(void *ptr, unsigned int size)
{
return wasm_runtime_realloc_internal(ptr, size);
}
void
wasm_runtime_free(void *ptr)
{
wasm_runtime_free_internal(ptr);
}
#if 0
static uint64 total_malloc = 0;
static uint64 total_free = 0;
void *
wasm_runtime_malloc(unsigned int size)
{
void *ret = wasm_runtime_malloc_internal(size + 8);
if (ret) {
total_malloc += size;
*(uint32 *)ret = size;
return (uint8 *)ret + 8;
}
else
return NULL;
}
void *
wasm_runtime_realloc(void *ptr, unsigned int size)
{
if (!ptr)
return wasm_runtime_malloc(size);
else {
uint8 *ptr_old = (uint8 *)ptr - 8;
uint32 size_old = *(uint32 *)ptr_old;
ptr = wasm_runtime_realloc_internal(ptr_old, size + 8);
if (ptr) {
total_free += size_old;
total_malloc += size;
*(uint32 *)ptr = size;
return (uint8 *)ptr + 8;
}
return NULL;
}
}
void
wasm_runtime_free(void *ptr)
{
if (ptr) {
uint8 *ptr_old = (uint8 *)ptr - 8;
uint32 size_old = *(uint32 *)ptr_old;
total_free += size_old;
wasm_runtime_free_internal(ptr_old);
}
}
void dump_memory_usage()
{
os_printf("Memory usage:\n");
os_printf(" total malloc: %"PRIu64"\n", total_malloc);
os_printf(" total free: %"PRIu64"\n", total_free);
}
#endif
#if BH_ENABLE_MEMORY_PROFILING != 0
void
memory_profile_print(const char *file, int line,
const char *func, int alloc)
@ -300,73 +379,5 @@ void memory_usage_summarize()
os_mutex_unlock(&profile_lock);
}
#endif /* end of BH_ENABLE_MEMORY_PROFILING */
#else /* else of MALLOC_MEMORY_FROM_SYSTEM */
void *
wasm_runtime_malloc(unsigned int size)
{
return malloc(size);
}
void *
wasm_runtime_realloc(void *ptr, unsigned int size)
{
return realloc(ptr, size);
}
void
wasm_runtime_free(void *ptr)
{
if (ptr)
free(ptr);
}
#if BH_ENABLE_MEMORY_PROFILING != 0
void *
wasm_runtime_malloc_profile(const char *file, int line,
const char *func, unsigned int size)
{
(void)file;
(void)line;
(void)func;
(void)memory_profiles_list;
(void)profile_lock;
(void)memory_in_use;
return malloc(size);
}
void *
wasm_runtime_realloc_profile(const char *file, int line,
const char *func, void *ptr, unsigned int size)
{
(void)file;
(void)line;
(void)func;
(void)memory_profiles_list;
(void)profile_lock;
(void)memory_in_use;
return realloc(ptr, size);
}
void
wasm_runtime_free_profile(const char *file, int line,
const char *func, void *ptr)
{
(void)file;
(void)line;
(void)func;
if (ptr)
free(ptr);
}
#endif /* end of BH_ENABLE_MEMORY_PROFILING */
#endif /* end of MALLOC_MEMORY_FROM_SYSTEM*/

View File

@ -275,6 +275,9 @@ register_natives(const char *module_name,
if (!(node = wasm_runtime_malloc(sizeof(NativeSymbolsNode))))
return false;
#if WASM_ENABLE_MEMORY_TRACING != 0
os_printf("Register native, size: %u\n", sizeof(NativeSymbolsNode));
#endif
node->module_name = module_name;
node->native_symbols = native_symbols;

View File

@ -791,6 +791,168 @@ wasm_runtime_destroy_exec_env(WASMExecEnv *exec_env)
wasm_exec_env_destroy(exec_env);
}
void
wasm_runtime_dump_module_mem_consumption(const WASMModuleCommon *module)
{
WASMModuleMemConsumption mem_conspn = { 0 };
#if WASM_ENABLE_INTERP != 0
if (module->module_type == Wasm_Module_Bytecode) {
wasm_get_module_mem_consumption((WASMModule*)module, &mem_conspn);
}
#endif
#if WASM_ENABLE_AOT != 0
if (module->module_type == Wasm_Module_AoT) {
aot_get_module_mem_consumption((AOTModule*)module, &mem_conspn);
}
#endif
os_printf("WASM module memory consumption, total size: %u\n",
mem_conspn.total_size);
os_printf(" module struct size: %u\n", mem_conspn.module_struct_size);
os_printf(" types size: %u\n", mem_conspn.types_size);
os_printf(" imports size: %u\n", mem_conspn.imports_size);
os_printf(" funcs size: %u\n", mem_conspn.functions_size);
os_printf(" tables size: %u\n", mem_conspn.tables_size);
os_printf(" memories size: %u\n", mem_conspn.memories_size);
os_printf(" globals size: %u\n", mem_conspn.globals_size);
os_printf(" exports size: %u\n", mem_conspn.exports_size);
os_printf(" table segs size: %u\n", mem_conspn.table_segs_size);
os_printf(" data segs size: %u\n", mem_conspn.data_segs_size);
os_printf(" const strings size: %u\n", mem_conspn.const_strs_size);
#if WASM_ENABLE_AOT != 0
os_printf(" aot code size: %u\n", mem_conspn.aot_code_size);
#endif
}
void
wasm_runtime_dump_module_inst_mem_consumption(const WASMModuleInstanceCommon
*module_inst)
{
WASMModuleInstMemConsumption mem_conspn = { 0 };
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) {
wasm_get_module_inst_mem_consumption((WASMModuleInstance*)module_inst,
&mem_conspn);
}
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT) {
aot_get_module_inst_mem_consumption((AOTModuleInstance*)module_inst,
&mem_conspn);
}
#endif
os_printf("WASM module inst memory consumption, total size: %u\n",
mem_conspn.total_size);
os_printf(" module inst struct size: %u\n",
mem_conspn.module_inst_struct_size);
os_printf(" memories size: %u\n", mem_conspn.memories_size);
os_printf(" app heap size: %u\n", mem_conspn.app_heap_size);
os_printf(" tables size: %u\n", mem_conspn.tables_size);
os_printf(" functions size: %u\n", mem_conspn.functions_size);
os_printf(" globals size: %u\n", mem_conspn.globals_size);
os_printf(" exports size: %u\n", mem_conspn.exports_size);
}
void
wasm_runtime_dump_exec_env_mem_consumption(const WASMExecEnv *exec_env)
{
uint32 total_size = offsetof(WASMExecEnv, wasm_stack.s.bottom)
+ exec_env->wasm_stack_size;
os_printf("Exec env memory consumption, total size: %u\n", total_size);
os_printf(" exec env struct size: %u\n",
offsetof(WASMExecEnv, wasm_stack.s.bottom));
#if WASM_ENABLE_INTERP != 0 && WASM_ENABLE_FAST_INTERP == 0
os_printf(" block addr cache size: %u\n",
sizeof(exec_env->block_addr_cache));
#endif
os_printf(" stack size: %u\n", exec_env->wasm_stack_size);
}
#if WASM_ENABLE_MEMORY_PROFILING != 0
uint32
gc_get_heap_highmark_size(void *heap);
void
wasm_runtime_dump_mem_consumption(WASMExecEnv *exec_env)
{
WASMModuleInstMemConsumption module_inst_mem_consps;
WASMModuleMemConsumption module_mem_consps;
WASMModuleInstanceCommon *module_inst_common;
WASMModuleCommon *module_common = NULL;
void *heap_handle = NULL;
uint32 total_size = 0, app_heap_peak_size = 0;
uint32 max_aux_stack_used = -1;
module_inst_common = exec_env->module_inst;
#if WASM_ENABLE_INTERP != 0
if (module_inst_common->module_type == Wasm_Module_Bytecode) {
WASMModuleInstance *wasm_module_inst =
(WASMModuleInstance*)module_inst_common;
WASMModule *wasm_module = wasm_module_inst->module;
module_common = (WASMModuleCommon*)wasm_module;
if (wasm_module_inst->memories) {
heap_handle = wasm_module_inst->memories[0]->heap_handle;
}
wasm_get_module_inst_mem_consumption
(wasm_module_inst, &module_inst_mem_consps);
wasm_get_module_mem_consumption
(wasm_module, &module_mem_consps);
if (wasm_module_inst->module->aux_stack_top_global_index != (uint32)-1)
max_aux_stack_used = wasm_module_inst->max_aux_stack_used;
}
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst_common->module_type == Wasm_Module_AoT) {
AOTModuleInstance *aot_module_inst =
(AOTModuleInstance*)module_inst_common;
AOTModule *aot_module =
(AOTModule*)aot_module_inst->aot_module.ptr;
module_common = (WASMModuleCommon*)aot_module;
if (aot_module_inst->memories.ptr) {
AOTMemoryInstance **memories =
(AOTMemoryInstance **)aot_module_inst->memories.ptr;
heap_handle = memories[0]->heap_handle.ptr;
}
aot_get_module_inst_mem_consumption
(aot_module_inst, &module_inst_mem_consps);
aot_get_module_mem_consumption
(aot_module, &module_mem_consps);
}
#endif
bh_assert(module_common != NULL);
if (heap_handle) {
app_heap_peak_size = gc_get_heap_highmark_size(heap_handle);
}
total_size = offsetof(WASMExecEnv, wasm_stack.s.bottom)
+ exec_env->wasm_stack_size
+ module_mem_consps.total_size
+ module_inst_mem_consps.total_size;
os_printf("\nMemory consumption summary (bytes):\n");
wasm_runtime_dump_module_mem_consumption(module_common);
wasm_runtime_dump_module_inst_mem_consumption(module_inst_common);
wasm_runtime_dump_exec_env_mem_consumption(exec_env);
os_printf("\nTotal memory consumption of module, module inst and "
"exec env: %u\n", total_size);
os_printf("Total interpreter stack used: %u\n",
exec_env->max_wasm_stack_used);
if (max_aux_stack_used != (uint32)-1)
os_printf("Total auxiliary stack used: %u\n", max_aux_stack_used);
else
os_printf("Total aux stack used: no enough info to profile\n");
os_printf("Total app heap used: %u\n", app_heap_peak_size);
}
#endif
WASMModuleInstanceCommon *
wasm_runtime_get_module_inst(WASMExecEnv *exec_env)
{
@ -1879,10 +2041,11 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst,
uint32 argc1 = 0, argv1[2] = { 0 };
uint32 total_argv_size = 0;
uint64 total_size;
uint32 argv_buf_offset;
uint32 argv_buf_offset = 0;
int32 i;
char *argv_buf, *p, *p_end;
uint32 *argv_offsets;
bool ret;
#if WASM_ENABLE_LIBC_WASI != 0
if (wasm_runtime_is_wasi_mode(module_inst)) {
@ -1961,8 +2124,11 @@ wasm_application_execute_main(WASMModuleInstanceCommon *module_inst,
argv1[1] = (uint32)wasm_runtime_addr_native_to_app(module_inst, argv_offsets);
}
return wasm_runtime_create_exec_env_and_call_wasm(module_inst, func,
argc1, argv1);
ret = wasm_runtime_create_exec_env_and_call_wasm(module_inst, func,
argc1, argv1);
if (argv_buf_offset)
wasm_runtime_module_free(module_inst, argv_buf_offset);
return ret;
}

View File

@ -43,6 +43,35 @@ typedef struct WASMModuleInstanceCommon {
uint8 module_inst_data[1];
} WASMModuleInstanceCommon;
typedef struct WASMModuleMemConsumption {
uint32 total_size;
uint32 module_struct_size;
uint32 types_size;
uint32 imports_size;
uint32 functions_size;
uint32 tables_size;
uint32 memories_size;
uint32 globals_size;
uint32 exports_size;
uint32 table_segs_size;
uint32 data_segs_size;
uint32 const_strs_size;
#if WASM_ENABLE_AOT != 0
uint32 aot_code_size;
#endif
} WASMModuleMemConsumption;
typedef struct WASMModuleInstMemConsumption {
uint32 total_size;
uint32 module_inst_struct_size;
uint32 memories_size;
uint32 app_heap_size;
uint32 tables_size;
uint32 globals_size;
uint32 functions_size;
uint32 exports_size;
} WASMModuleInstMemConsumption;
#if WASM_ENABLE_LIBC_WASI != 0
typedef struct WASIContext {
/* Use offset but not native address, since these fields are
@ -432,6 +461,16 @@ wasm_runtime_invoke_native_raw(WASMExecEnv *exec_env, void *func_ptr,
void *attachment,
uint32 *argv, uint32 argc, uint32 *ret);
void
wasm_runtime_dump_module_mem_consumption(const WASMModuleCommon *module);
void
wasm_runtime_dump_module_inst_mem_consumption(const WASMModuleInstanceCommon
*module_inst);
void
wasm_runtime_dump_exec_env_mem_consumption(const WASMExecEnv *exec_env);
#ifdef __cplusplus
}
#endif