introduce WAMR memory profiling tool (experimental) (#390)
This commit is contained in:
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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*/
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user