Implement performance profiler and call stack dump, and update toolchain document (#501)

And remove redundant FAST_INTERP macros in wasm_interp_fast.c, and fix wamrc --help wrong line order issue.

Signed-off-by: Wenyong Huang <wenyong.huang@intel.com>
This commit is contained in:
Wenyong Huang
2021-01-17 23:23:10 -06:00
committed by GitHub
parent 794028a968
commit 240ca2ed46
26 changed files with 752 additions and 109 deletions

View File

@ -180,6 +180,16 @@
#define WASM_ENABLE_MEMORY_TRACING 0
#endif
/* Performance profiling */
#ifndef WASM_ENABLE_PERF_PROFILING
#define WASM_ENABLE_PERF_PROFILING 0
#endif
/* Dump call stack */
#ifndef WASM_ENABLE_DUMP_CALL_STACK
#define WASM_ENABLE_DUMP_CALL_STACK 0
#endif
/* Heap verification */
#ifndef BH_ENABLE_GC_VERIFY
#define BH_ENABLE_GC_VERIFY 0

View File

@ -2174,6 +2174,9 @@ aot_convert_wasm_module(WASMModule *wasm_module,
#endif
#if WASM_ENABLE_SIMD != 0
option.enable_simd = true;
#endif
#if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0)
option.enable_aux_stack_frame = true;
#endif
comp_ctx = aot_create_comp_context(comp_data, &option);
if (!comp_ctx) {

View File

@ -29,6 +29,14 @@ typedef struct {
#define REG_ATOMIC_WAIT_SYM()
#endif
#if (WASM_ENABLE_PERF_PROFILING != 0) || (WASM_ENABLE_DUMP_CALL_STACK != 0)
#define REG_AOT_TRACE_SYM() \
REG_SYM(aot_alloc_frame), \
REG_SYM(aot_free_frame),
#else
#define REG_AOT_TRACE_SYM()
#endif
#if (defined(_WIN32) || defined(_WIN32_)) && defined(NDEBUG)
#define REG_COMMON_SYMBOLS \
REG_SYM(aot_set_exception_with_id), \
@ -39,7 +47,8 @@ typedef struct {
REG_SYM(aot_memset), \
REG_SYM(aot_memmove), \
REG_BULK_MEMORY_SYM() \
REG_ATOMIC_WAIT_SYM()
REG_ATOMIC_WAIT_SYM() \
REG_AOT_TRACE_SYM()
#else /* else of (defined(_WIN32) || defined(_WIN32_)) && defined(NDEBUG) */
#define REG_COMMON_SYMBOLS \
REG_SYM(aot_set_exception_with_id), \
@ -62,7 +71,8 @@ typedef struct {
REG_SYM(rint), \
REG_SYM(rintf), \
REG_BULK_MEMORY_SYM() \
REG_ATOMIC_WAIT_SYM()
REG_ATOMIC_WAIT_SYM() \
REG_AOT_TRACE_SYM()
#endif /* end of (defined(_WIN32) || defined(_WIN32_)) && defined(NDEBUG) */
#define CHECK_RELOC_OFFSET(data_size) do { \

View File

@ -814,6 +814,15 @@ aot_instantiate(AOTModule *module, bool is_sub_inst,
#endif
module_inst->default_wasm_stack_size = stack_size;
#if WASM_ENABLE_PERF_PROFILING != 0
total_size = (uint64)sizeof(AOTFuncPerfProfInfo) *
(module->import_func_count + module->func_count);
if (!(module_inst->func_perf_profilings.ptr =
runtime_malloc(total_size, error_buf, error_buf_size))) {
goto fail;
}
#endif
/* Execute __post_instantiate function and start function*/
if (!execute_post_inst_function(module_inst)
|| !execute_start_function(module_inst)) {
@ -866,6 +875,11 @@ aot_deinstantiate(AOTModuleInstance *module_inst, bool is_sub_inst)
wasm_runtime_destroy_wasi((WASMModuleInstanceCommon*)module_inst);
#endif
#if WASM_ENABLE_PERF_PROFILING != 0
if (module_inst->func_perf_profilings.ptr)
wasm_runtime_free(module_inst->func_perf_profilings.ptr);
#endif
if (module_inst->memories.ptr)
memories_deinstantiate(module_inst);
@ -1128,16 +1142,38 @@ aot_call_function(WASMExecEnv *exec_env,
cell_num += wasm_value_type_cell_num(ext_ret_types[i]);
}
#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
if (!aot_alloc_frame(exec_env, function->func_index)) {
wasm_runtime_free(argv1);
return false;
}
#endif
ret = invoke_native_internal(exec_env, function->u.func.func_ptr,
func_type, NULL, NULL, argv1, argc, argv);
if (!ret || aot_get_exception(module_inst)) {
if (argv1 != argv1_buf)
wasm_runtime_free(argv1);
if (clear_wasi_proc_exit_exception(module_inst))
return true;
return false;
ret = true;
else
ret = false;
}
#if WASM_ENABLE_DUMP_CALL_STACK != 0
if (!ret) {
aot_dump_call_stack(exec_env);
}
#endif
#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
aot_free_frame(exec_env);
#endif
if (!ret)
return ret;
/* Get extra result values */
switch (func_type->types[func_type->param_count]) {
case VALUE_TYPE_I32:
@ -1161,10 +1197,28 @@ aot_call_function(WASMExecEnv *exec_env,
return true;
}
else {
#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
if (!aot_alloc_frame(exec_env, function->func_index)) {
return false;
}
#endif
ret = invoke_native_internal(exec_env, function->u.func.func_ptr,
func_type, NULL, NULL, argv, argc, argv);
if (clear_wasi_proc_exit_exception(module_inst))
return true;
ret = true;
#if WASM_ENABLE_DUMP_CALL_STACK != 0
if (aot_get_exception(module_inst)) {
aot_dump_call_stack(exec_env);
}
#endif
#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
aot_free_frame(exec_env);
#endif
return ret && !aot_get_exception(module_inst) ? true : false;
}
}
@ -2224,3 +2278,134 @@ aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst,
}
#endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0)
|| (WASM_ENABLE_MEMORY_TRACING != 0) */
#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
static const char *
get_func_name_from_index(const AOTModuleInstance *module_inst,
uint32 func_index)
{
const char *func_name = NULL;
AOTModule *module = module_inst->aot_module.ptr;
if (func_index < module->import_func_count) {
func_name = module->import_funcs[func_index].func_name;
}
else {
uint32 i;
for (i = 0; i < module->export_count; i++) {
AOTExport export = module->exports[i];
if (export.index == func_index
&& export.kind == EXPORT_KIND_FUNC) {
func_name = export.name;
break;
}
}
}
return func_name;
}
bool
aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index)
{
AOTFrame *frame =
wasm_exec_env_alloc_wasm_frame(exec_env, sizeof(AOTFrame));
#if WASM_ENABLE_PERF_PROFILING != 0
AOTModuleInstance *module_inst =
(AOTModuleInstance*)exec_env->module_inst;
AOTFuncPerfProfInfo *func_perf_prof =
(AOTFuncPerfProfInfo*)module_inst->func_perf_profilings.ptr + func_index;
#endif
if (!frame) {
aot_set_exception((AOTModuleInstance*)exec_env->module_inst,
"auxiliary call stack overflow");
return false;
}
#if WASM_ENABLE_PERF_PROFILING != 0
frame->time_started = os_time_get_boot_microsecond();
frame->func_perf_prof_info = func_perf_prof;
#endif
frame->prev_frame = (AOTFrame *)exec_env->cur_frame;
exec_env->cur_frame = (struct WASMInterpFrame *)frame;
frame->func_index = func_index;
return true;
}
void
aot_free_frame(WASMExecEnv *exec_env)
{
AOTFrame *cur_frame = (AOTFrame *)exec_env->cur_frame;
AOTFrame *prev_frame = cur_frame->prev_frame;
#if WASM_ENABLE_PERF_PROFILING != 0
cur_frame->func_perf_prof_info->total_exec_time +=
os_time_get_boot_microsecond() - cur_frame->time_started;
cur_frame->func_perf_prof_info->total_exec_cnt++;
#endif
wasm_exec_env_free_wasm_frame(exec_env, cur_frame);
exec_env->cur_frame = (struct WASMInterpFrame *)prev_frame;
}
#endif /* end of (WASM_ENABLE_DUMP_CALL_STACK != 0)
|| (WASM_ENABLE_PERF_PROFILING != 0) */
#if WASM_ENABLE_DUMP_CALL_STACK != 0
void
aot_dump_call_stack(WASMExecEnv *exec_env)
{
AOTFrame *cur_frame = (AOTFrame *)exec_env->cur_frame;
AOTModuleInstance *module_inst =
(AOTModuleInstance *)exec_env->module_inst;
const char *func_name;
uint32 n = 0;
os_printf("\n");
while (cur_frame) {
func_name =
get_func_name_from_index(module_inst, cur_frame->func_index);
/* function name not exported, print number instead */
if (func_name == NULL) {
os_printf("#%02d $f%d \n", n, cur_frame->func_index);
}
else {
os_printf("#%02d %s \n", n, func_name);
}
cur_frame = cur_frame->prev_frame;
n++;
}
os_printf("\n");
}
#endif /* end of WASM_ENABLE_DUMP_CALL_STACK */
#if WASM_ENABLE_PERF_PROFILING != 0
void
aot_dump_perf_profiling(const AOTModuleInstance *module_inst)
{
AOTFuncPerfProfInfo *perf_prof = (AOTFuncPerfProfInfo *)
module_inst->func_perf_profilings.ptr;
AOTModule *module = (AOTModule *)module_inst->aot_module.ptr;
uint32 total_func_count = module->import_func_count + module->func_count, i;
const char *func_name;
os_printf("Performance profiler data:\n");
for (i = 0; i < total_func_count; i++, perf_prof++) {
func_name = get_func_name_from_index(module_inst, i);
if (func_name)
os_printf(" func %s, execution time: %.3f ms, execution count: %d times\n",
func_name, perf_prof->total_exec_time / 1000.0f,
perf_prof->total_exec_cnt);
else
os_printf(" func %d, execution time: %.3f ms, execution count: %d times\n",
i, perf_prof->total_exec_time / 1000.0f,
perf_prof->total_exec_cnt);
}
}
#endif /* end of WASM_ENABLE_PERF_PROFILING */

View File

@ -281,8 +281,13 @@ typedef struct AOTModuleInstance {
uint32 llvm_stack;
uint32 default_wasm_stack_size;
uint32 __padding;
/* function performance profiling info list */
AOTPointer func_perf_profilings;
/* reserved */
uint32 reserved[11];
uint32 reserved[8];
union {
uint64 _make_it_8_byte_aligned_;
@ -311,6 +316,24 @@ typedef struct AOTTargetInfo {
char arch[16];
} AOTTargetInfo;
typedef struct AOTFuncPerfProfInfo
{
/* total execution time */
uint64 total_exec_time;
/* total execution count */
uint32 total_exec_cnt;
} AOTFuncPerfProfInfo;
/* AOT auxiliary call stack */
typedef struct AOTFrame {
struct AOTFrame *prev_frame;
uint32 func_index;
#if WASM_ENABLE_PERF_PROFILING != 0
uint64 time_started;
AOTFuncPerfProfInfo *func_perf_prof_info;
#endif
} AOTFrame;
/**
* Load a AOT module from aot file buffer
* @param buf the byte buffer which contains the AOT file data
@ -568,6 +591,18 @@ void
aot_get_module_inst_mem_consumption(const AOTModuleInstance *module_inst,
WASMModuleInstMemConsumption *mem_conspn);
bool
aot_alloc_frame(WASMExecEnv *exec_env, uint32 func_index);
void
aot_free_frame(WASMExecEnv *exec_env);
void
aot_dump_call_stack(WASMExecEnv *exec_env);
void
aot_dump_perf_profiling(const AOTModuleInstance *module_inst);
#ifdef __cplusplus
} /* end of extern "C" */
#endif

View File

@ -960,6 +960,23 @@ wasm_runtime_dump_mem_consumption(WASMExecEnv *exec_env)
#endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0)
|| (WASM_ENABLE_MEMORY_TRACING != 0) */
#if WASM_ENABLE_PERF_PROFILING != 0
void
wasm_runtime_dump_perf_profiling(WASMModuleInstanceCommon *module_inst)
{
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) {
wasm_dump_perf_profiling((WASMModuleInstance*)module_inst);
}
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT) {
aot_dump_perf_profiling((AOTModuleInstance*)module_inst);
}
#endif
}
#endif
WASMModuleInstanceCommon *
wasm_runtime_get_module_inst(WASMExecEnv *exec_env)
{
@ -3453,3 +3470,22 @@ wasm_runtime_join_thread(wasm_thread_t tid, void **retval)
}
#endif
#if WASM_ENABLE_DUMP_CALL_STACK != 0
void
wasm_runtime_dump_call_stack(WASMExecEnv *exec_env)
{
WASMModuleInstanceCommon *module_inst
= wasm_exec_env_get_module_inst(exec_env);
#if WASM_ENABLE_INTERP != 0
if (module_inst->module_type == Wasm_Module_Bytecode) {
wasm_interp_dump_call_stack(exec_env);
}
#endif
#if WASM_ENABLE_AOT != 0
if (module_inst->module_type == Wasm_Module_AoT) {
aot_dump_call_stack(exec_env);
}
#endif
}
#endif /* end of WASM_ENABLE_DUMP_CALL_STACK */

View File

@ -8,6 +8,45 @@
#include "aot_emit_control.h"
#include "../aot/aot_runtime.h"
#define GET_AOT_FUNCTION(name, argc) do { \
if (!(func_type = LLVMFunctionType(ret_type, param_types, \
argc, false))) { \
aot_set_last_error("llvm add function type failed."); \
return false; \
} \
if (comp_ctx->is_jit_mode) { \
/* JIT mode, call the function directly */ \
if (!(func_ptr_type = LLVMPointerType(func_type, 0))) { \
aot_set_last_error("llvm add pointer type failed."); \
return false; \
} \
if (!(value = I64_CONST((uint64)(uintptr_t)name)) \
|| !(func = LLVMConstIntToPtr(value, func_ptr_type))) { \
aot_set_last_error("create LLVM value failed."); \
return false; \
} \
} \
else { \
char *func_name = #name; \
/* AOT mode, delcare the function */ \
if (!(func = LLVMGetNamedFunction(comp_ctx->module, func_name)) \
&& !(func = LLVMAddFunction(comp_ctx->module, \
func_name, func_type))) { \
aot_set_last_error("llvm add function failed."); \
return false; \
} \
} \
} while (0)
#define ADD_BASIC_BLOCK(block, name) do { \
if (!(block = LLVMAppendBasicBlockInContext(comp_ctx->context, \
func_ctx->func, \
name))) { \
aot_set_last_error("llvm add basic block failed."); \
goto fail; \
} \
} while (0)
static bool
create_func_return_block(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
@ -239,6 +278,91 @@ call_aot_invoke_native_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
return true;
}
#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
static bool
call_aot_alloc_frame_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
LLVMValueRef func_idx)
{
LLVMValueRef param_values[2], ret_value, value, func;
LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
LLVMBasicBlockRef block_curr = LLVMGetInsertBlock(comp_ctx->builder);
LLVMBasicBlockRef frame_alloc_fail, frame_alloc_success;
AOTFuncType *aot_func_type = func_ctx->aot_func->func_type;
param_types[0] = comp_ctx->exec_env_type;
param_types[1] = I32_TYPE;
ret_type = INT8_TYPE;
GET_AOT_FUNCTION(aot_alloc_frame, 2);
param_values[0] = func_ctx->exec_env;
param_values[1] = func_idx;
if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func,
param_values, 2,
"call_aot_alloc_frame"))) {
aot_set_last_error("llvm build call failed.");
return false;
}
if (!(ret_value = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGT,
ret_value, I8_ZERO, "frame_alloc_ret"))) {
aot_set_last_error("llvm build icmp failed.");
return false;
}
ADD_BASIC_BLOCK(frame_alloc_fail, "frame_alloc_fail");
ADD_BASIC_BLOCK(frame_alloc_success, "frame_alloc_success");
LLVMMoveBasicBlockAfter(frame_alloc_fail, block_curr);
LLVMMoveBasicBlockAfter(frame_alloc_success, block_curr);
if (!LLVMBuildCondBr(comp_ctx->builder, ret_value,
frame_alloc_success, frame_alloc_fail)) {
aot_set_last_error("llvm build cond br failed.");
return false;
}
/* If frame alloc failed, return this function
so the runtime can catch the exception */
LLVMPositionBuilderAtEnd(comp_ctx->builder, frame_alloc_fail);
if (!aot_build_zero_function_ret(comp_ctx, aot_func_type)) {
return false;
}
LLVMPositionBuilderAtEnd(comp_ctx->builder, frame_alloc_success);
return true;
fail:
return false;
}
static bool
call_aot_free_frame_func(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx)
{
LLVMValueRef param_values[1], ret_value, value, func;
LLVMTypeRef param_types[1], ret_type, func_type, func_ptr_type;
param_types[0] = comp_ctx->exec_env_type;
ret_type = INT8_TYPE;
GET_AOT_FUNCTION(aot_free_frame, 1);
param_values[0] = func_ctx->exec_env;
if (!(ret_value = LLVMBuildCall(comp_ctx->builder, func,
param_values, 1,
"call_aot_free_frame"))) {
aot_set_last_error("llvm build call failed.");
return false;
}
return true;
}
#endif /* end of (WASM_ENABLE_DUMP_CALL_STACK != 0)
|| (WASM_ENABLE_PERF_PROFILING != 0) */
static bool
check_stack_boundary(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
uint32 callee_cell_num)
@ -334,6 +458,19 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
/* Get param cell number */
param_cell_num = func_type->param_cell_num;
#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
if (comp_ctx->enable_aux_stack_frame) {
LLVMValueRef func_idx_const;
if (!(func_idx_const = I32_CONST(func_idx))) {
aot_set_last_error("llvm build const failed.");
return false;
}
if (!call_aot_alloc_frame_func(comp_ctx, func_ctx, func_idx_const))
return false;
}
#endif
/* Allocate memory for parameters.
* Parameters layout:
* - exec env
@ -485,13 +622,20 @@ aot_compile_op_call(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
}
}
#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
if (comp_ctx->enable_aux_stack_frame) {
if (!call_aot_free_frame_func(comp_ctx, func_ctx))
goto fail;
}
#endif
ret = true;
fail:
if (param_types)
wasm_runtime_free(param_types);
if (param_values)
wasm_runtime_free(param_values);
return ret;
return ret;
}
static bool
@ -889,6 +1033,13 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
}
#endif
#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
if (comp_ctx->enable_aux_stack_frame) {
if (!call_aot_alloc_frame_func(comp_ctx, func_ctx, func_idx))
goto fail;
}
#endif
/* Add basic blocks */
block_call_import =
LLVMAppendBasicBlockInContext(comp_ctx->context, func_ctx->func,
@ -1066,6 +1217,13 @@ aot_compile_op_call_indirect(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
PUSH(result_phis[i], func_type->types[func_param_count + i]);
}
#if (WASM_ENABLE_DUMP_CALL_STACK != 0) || (WASM_ENABLE_PERF_PROFILING != 0)
if (comp_ctx->enable_aux_stack_frame) {
if (!call_aot_free_frame_func(comp_ctx, func_ctx))
goto fail;
}
#endif
ret = true;
fail:

View File

@ -1163,6 +1163,9 @@ aot_create_comp_context(AOTCompData *comp_data,
if (option->enable_simd)
comp_ctx->enable_simd = true;
if (option->enable_aux_stack_frame)
comp_ctx->enable_aux_stack_frame = true;
if (option->is_jit_mode) {
char *triple_jit = NULL;

View File

@ -223,6 +223,9 @@ typedef struct AOTCompContext {
/* 128-bit SIMD */
bool enable_simd;
/* generate auxiliary stack frame */
bool enable_aux_stack_frame;
/* Thread Manager */
bool enable_thread_mgr;
@ -271,6 +274,7 @@ typedef struct AOTCompOption{
bool enable_thread_mgr;
bool enable_tail_call;
bool enable_simd;
bool enable_aux_stack_frame;
bool is_sgx_platform;
uint32 opt_level;
uint32 size_level;

View File

@ -43,6 +43,7 @@ typedef struct AOTCompOption{
bool enable_thread_mgr;
bool enable_tail_call;
bool enable_simd;
bool enable_aux_stack_frame;
bool is_sgx_platform;
uint32_t opt_level;
uint32_t size_level;

View File

@ -227,7 +227,6 @@ wasm_runtime_free(void *ptr);
WASM_RUNTIME_API_EXTERN package_type_t
get_package_type(const uint8_t *buf, uint32_t size);
#if WASM_ENABLE_MULTI_MODULE != 0
/**
* It is a callback for WAMR providing by embedding to load a module file
* into a buffer
@ -275,7 +274,6 @@ wasm_runtime_register_module(const char *module_name, wasm_module_t module,
*/
WASM_RUNTIME_API_EXTERN wasm_module_t
wasm_runtime_find_module_registered(const char *module_name);
#endif /* WASM_ENABLE_MULTI_MODULE */
/**
* Load a WASM module from a specified byte buffer. The byte buffer can be
@ -787,7 +785,14 @@ wasm_runtime_get_user_data(wasm_exec_env_t exec_env);
WASM_RUNTIME_API_EXTERN void
wasm_runtime_dump_mem_consumption(wasm_exec_env_t exec_env);
#if WASM_ENABLE_THREAD_MGR != 0
/**
* Dump runtime performance profiler data of each function
*
* @param module_inst the WASM module instance to profile
*/
WASM_RUNTIME_API_EXTERN void
wasm_runtime_dump_perf_profiling(wasm_module_inst_t module_inst);
/* wasm thread callback function type */
typedef void* (*wasm_thread_callback_t)(wasm_exec_env_t, void *);
/* wasm thread type */
@ -844,7 +849,14 @@ wasm_runtime_spawn_thread(wasm_exec_env_t exec_env, wasm_thread_t *tid,
*/
WASM_RUNTIME_API_EXTERN int32_t
wasm_runtime_join_thread(wasm_thread_t tid, void **retval);
#endif
/**
* dump the call stack
*
* @param exec_env the execution environment
*/
WASM_RUNTIME_API_EXTERN void
wasm_runtime_dump_call_stack(wasm_exec_env_t exec_env);
#ifdef __cplusplus
}

View File

@ -26,6 +26,10 @@ typedef struct WASMInterpFrame {
/* Instruction pointer of the bytecode array. */
uint8 *ip;
#if WASM_ENABLE_PERF_PROFILING != 0
uint64 time_started;
#endif
#if WASM_ENABLE_FAST_INTERP != 0
/* return offset of the first return value of current frame.
the callee will put return values here continuously */
@ -74,11 +78,6 @@ wasm_interp_call_wasm(struct WASMModuleInstance *module_inst,
struct WASMFunctionInstance *function,
uint32 argc, uint32 argv[]);
#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
void
wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -900,8 +900,12 @@ ALLOC_FRAME(WASMExecEnv *exec_env, uint32 size, WASMInterpFrame *prev_frame)
{
WASMInterpFrame *frame = wasm_exec_env_alloc_wasm_frame(exec_env, size);
if (frame)
if (frame) {
frame->prev_frame = prev_frame;
#if WASM_ENABLE_PERF_PROFILING != 0
frame->time_started = os_time_get_boot_microsecond();
#endif
}
else {
wasm_set_exception((WASMModuleInstance*)exec_env->module_inst,
"stack overflow");
@ -913,6 +917,13 @@ ALLOC_FRAME(WASMExecEnv *exec_env, uint32 size, WASMInterpFrame *prev_frame)
static inline void
FREE_FRAME(WASMExecEnv *exec_env, WASMInterpFrame *frame)
{
#if WASM_ENABLE_PERF_PROFILING != 0
if (frame->function) {
frame->function->total_exec_time += os_time_get_boot_microsecond()
- frame->time_started;
frame->function->total_exec_cnt++;
}
#endif
wasm_exec_env_free_wasm_frame(exec_env, frame);
}
@ -3361,7 +3372,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst,
}
}
else {
#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
#if WASM_ENABLE_DUMP_CALL_STACK != 0
wasm_interp_dump_call_stack(exec_env);
#endif
LOG_DEBUG("meet an exception %s", wasm_get_exception(module_inst));

View File

@ -909,8 +909,12 @@ ALLOC_FRAME(WASMExecEnv *exec_env, uint32 size, WASMInterpFrame *prev_frame)
{
WASMInterpFrame *frame = wasm_exec_env_alloc_wasm_frame(exec_env, size);
if (frame)
if (frame) {
frame->prev_frame = prev_frame;
#if WASM_ENABLE_PERF_PROFILING != 0
frame->time_started = os_time_get_boot_microsecond();
#endif
}
else {
wasm_set_exception((WASMModuleInstance*)exec_env->module_inst,
"stack overflow");
@ -922,6 +926,13 @@ ALLOC_FRAME(WASMExecEnv *exec_env, uint32 size, WASMInterpFrame *prev_frame)
static inline void
FREE_FRAME(WASMExecEnv *exec_env, WASMInterpFrame *frame)
{
#if WASM_ENABLE_PERF_PROFILING != 0
if (frame->function) {
frame->function->total_exec_time += os_time_get_boot_microsecond()
- frame->time_started;
frame->function->total_exec_cnt++;
}
#endif
wasm_exec_env_free_wasm_frame(exec_env, frame);
}
@ -1086,9 +1097,6 @@ wasm_interp_dump_op_count()
#else
#define HANDLE_OP(opcode) HANDLE_##opcode
#endif
#if WASM_ENABLE_FAST_INTERP == 0
#define FETCH_OPCODE_AND_DISPATCH() goto *handle_table[*frame_ip++]
#else
#if WASM_ENABLE_ABS_LABEL_ADDR != 0
#define FETCH_OPCODE_AND_DISPATCH() do { \
const void *p_label_addr = *(void**)frame_ip; \
@ -1103,7 +1111,6 @@ wasm_interp_dump_op_count()
goto *p_label_addr; \
} while (0)
#endif
#endif
#define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH()
#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
@ -1113,9 +1120,7 @@ wasm_interp_dump_op_count()
#endif /* end of WASM_ENABLE_LABELS_AS_VALUES */
#if WASM_ENABLE_FAST_INTERP != 0
static void **global_handle_table;
#endif
static void
wasm_interp_call_func_bytecode(WASMModuleInstance *module,
@ -1150,13 +1155,11 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
#define HANDLE_OPCODE(op) &&HANDLE_##op
DEFINE_GOTO_TABLE (const void*, handle_table);
#undef HANDLE_OPCODE
#if WASM_ENABLE_FAST_INTERP != 0
if (exec_env == NULL) {
global_handle_table = (void **)handle_table;
return;
}
#endif
#endif
#if WASM_ENABLE_LABELS_AS_VALUES == 0
while (frame_ip < frame_ip_end) {
@ -3330,7 +3333,6 @@ recover_br_info:
#endif
}
#if WASM_ENABLE_FAST_INTERP != 0
void **
wasm_interp_get_handle_table()
{
@ -3339,7 +3341,6 @@ wasm_interp_get_handle_table()
wasm_interp_call_func_bytecode(&module, NULL, NULL, NULL);
return global_handle_table;
}
#endif
void
wasm_interp_call_wasm(WASMModuleInstance *module_inst,
@ -3412,7 +3413,7 @@ wasm_interp_call_wasm(WASMModuleInstance *module_inst,
argv[i] = *(frame->lp + i);
}
else {
#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
#if WASM_ENABLE_DUMP_CALL_STACK != 0
wasm_interp_dump_call_stack(exec_env);
#endif
}

View File

@ -1448,7 +1448,6 @@ load_user_section(const uint8 *buf, const uint8 *buf_end, WASMModule *module,
static bool
wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
BlockAddr *block_addr_cache,
char *error_buf, uint32 error_buf_size);
#if WASM_ENABLE_FAST_INTERP != 0
@ -1472,9 +1471,7 @@ load_from_sections(WASMModule *module, WASMSection *sections,
uint32 aux_stack_top = (uint32)-1, global_index, func_index, i;
uint32 aux_data_end_global_index = (uint32)-1;
uint32 aux_heap_base_global_index = (uint32)-1;
BlockAddr *block_addr_cache;
WASMType *func_type;
uint64 total_size;
/* Find code and function sections if have */
while (section) {
@ -1746,22 +1743,13 @@ load_from_sections(WASMModule *module, WASMSection *sections,
handle_table = wasm_interp_get_handle_table();
#endif
total_size = sizeof(BlockAddr) * (uint64)BLOCK_ADDR_CACHE_SIZE * BLOCK_ADDR_CONFLICT_SIZE;
if (!(block_addr_cache = loader_malloc
(total_size, error_buf, error_buf_size))) {
return false;
}
for (i = 0; i < module->function_count; i++) {
WASMFunction *func = module->functions[i];
memset(block_addr_cache, 0, (uint32)total_size);
if (!wasm_loader_prepare_bytecode(module, func, block_addr_cache,
if (!wasm_loader_prepare_bytecode(module, func,
error_buf, error_buf_size)) {
wasm_runtime_free(block_addr_cache);
return false;
}
}
wasm_runtime_free(block_addr_cache);
if (!module->possible_memory_grow) {
WASMMemoryImport *memory_import;
@ -4251,7 +4239,6 @@ fail:
static bool
wasm_loader_prepare_bytecode(WASMModule *module, WASMFunction *func,
BlockAddr *block_addr_cache,
char *error_buf, uint32 error_buf_size)
{
uint8 *p = func->code, *p_end = func->code + func->code_size, *p_org;

View File

@ -1657,6 +1657,49 @@ wasm_get_exception(WASMModuleInstance *module_inst)
return module_inst->cur_exception;
}
#if WASM_ENABLE_PERF_PROFILING != 0
void
wasm_dump_perf_profiling(const WASMModuleInstance *module_inst)
{
WASMExportFuncInstance *export_func;
WASMFunctionInstance *func_inst;
char *func_name;
uint32 i, j;
os_printf("Performance profiler data:\n");
for (i = 0; i < module_inst->function_count; i++) {
func_inst = module_inst->functions + i;
if (func_inst->is_import_func) {
func_name = func_inst->u.func_import->field_name;
}
#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
else if (func_inst->u.func->field_name) {
func_name = func_inst->u.func->field_name;
}
#endif
else {
func_name = NULL;
for (j = 0; j < module_inst->export_func_count; j++) {
export_func = module_inst->export_functions + j;
if (export_func->function == func_inst) {
func_name = export_func->name;
break;
}
}
}
if (func_name)
os_printf(" func %s, execution time: %.3f ms, execution count: %d times\n",
func_name, module_inst->functions[i].total_exec_time / 1000.0f,
module_inst->functions[i].total_exec_cnt);
else
os_printf(" func %d, execution time: %.3f ms, execution count: %d times\n",
i, module_inst->functions[i].total_exec_time / 1000.0f,
module_inst->functions[i].total_exec_cnt);
}
}
#endif
uint32
wasm_module_malloc(WASMModuleInstance *module_inst, uint32 size,
void **p_native_addr)
@ -2205,7 +2248,7 @@ wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module_inst,
#endif /* end of (WASM_ENABLE_MEMORY_PROFILING != 0)
|| (WASM_ENABLE_MEMORY_TRACING != 0) */
#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
#if WASM_ENABLE_DUMP_CALL_STACK != 0
void
wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env)
{
@ -2214,18 +2257,33 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env)
WASMInterpFrame *cur_frame =
wasm_exec_env_get_cur_frame(exec_env);
WASMFunctionInstance *func_inst;
WASMExportFuncInstance *export_func;
const char *func_name = NULL;
uint32 n;
uint32 n, i;
os_printf("\n");
for (n = 0; cur_frame && cur_frame->function; n++) {
func_name = NULL;
func_inst = cur_frame->function;
if (func_inst->is_import_func) {
func_name = func_inst->u.func_import->field_name;
}
else {
#if WASM_ENABLE_CUSTOM_NAME_SECTION != 0
func_name = func_inst->u.func->field_name;
#endif
/* if custom name section is not generated,
search symbols from export table */
if (!func_name) {
for (i = 0; i < module_inst->export_func_count; i++) {
export_func = module_inst->export_functions + i;
if (export_func->function == func_inst) {
func_name = export_func->name;
break;
}
}
}
}
/* function name not exported, print number instead */
@ -2240,4 +2298,4 @@ wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env)
}
os_printf("\n");
}
#endif /* end of WASM_ENABLE_CUSTOM_NAME_SECTION */
#endif /* end of WASM_ENABLE_DUMP_CALL_STACK */

View File

@ -120,6 +120,12 @@ struct WASMFunctionInstance {
WASMModuleInstance *import_module_inst;
WASMFunctionInstance *import_func_inst;
#endif
#if WASM_ENABLE_PERF_PROFILING != 0
/* total execution time */
uint64 total_exec_time;
/* total execution count */
uint32 total_exec_cnt;
#endif
};
typedef struct WASMExportFuncInstance {
@ -281,12 +287,15 @@ wasm_instantiate(WASMModule *module, bool is_sub_inst,
uint32 stack_size, uint32 heap_size,
char *error_buf, uint32 error_buf_size);
void
wasm_dump_perf_profiling(const WASMModuleInstance *module_inst);
void
wasm_deinstantiate(WASMModuleInstance *module_inst, bool is_sub_inst);
WASMFunctionInstance *
wasm_lookup_function(const WASMModuleInstance *module_inst,
const char *name, const char *signature);
const char *name, const char *signature);
#if WASM_ENABLE_MULTI_MODULE != 0
WASMGlobalInstance *
@ -383,6 +392,12 @@ wasm_get_module_mem_consumption(const WASMModule *module,
void
wasm_get_module_inst_mem_consumption(const WASMModuleInstance *module,
WASMModuleInstMemConsumption *mem_conspn);
#if WASM_ENABLE_DUMP_CALL_STACK != 0
void
wasm_interp_dump_call_stack(struct WASMExecEnv *exec_env);
#endif
#ifdef __cplusplus
}
#endif

View File

@ -616,7 +616,7 @@ pthread_join_wrapper(wasm_exec_env_t exec_env, uint32 thread,
/* validate addr before join thread, otherwise
the module_inst may be freed */
if (!validate_app_addr(retval_offset, sizeof(uint32))) {
if (!validate_app_addr(retval_offset, sizeof(void *))) {
/* Join failed, but we don't want to terminate all threads,
do not spread exception here */
wasm_runtime_set_exception(module_inst, NULL);