debug-interp: Only add lock when signal_flag is SIG_SINGSTEP (#3704)

As reported in #3500, when debug interpreter is enabled, the classic interpreter
performs a lock operation to read `exec_env->current_status->signal_flag` and
do further handling before fetching next opcode, which makes the interpreter
run slower.

This PR atomic loads the `exec_env->current_status->signal_flag` without mutex
lock when 32-bit atomic load is supported, and only adding lock for further
handling when the signal_flag is WAMR_SIG_SINGSTEP, which improves the
performance.
This commit is contained in:
Wenyong Huang
2024-08-14 09:03:01 +08:00
committed by GitHub
parent 37d7439ef9
commit da25906ed4
2 changed files with 60 additions and 27 deletions

View File

@ -1399,6 +1399,23 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
#endif /* WASM_ENABLE_DEBUG_INTERP */ #endif /* WASM_ENABLE_DEBUG_INTERP */
#endif /* WASM_ENABLE_THREAD_MGR */ #endif /* WASM_ENABLE_THREAD_MGR */
#if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0
#if BH_ATOMIC_32_IS_ATOMIC != 0
#define GET_SIGNAL_FLAG() \
do { \
signal_flag = \
BH_ATOMIC_32_LOAD(exec_env->current_status->signal_flag); \
} while (0)
#else
#define GET_SIGNAL_FLAG() \
do { \
os_mutex_lock(&exec_env->wait_lock); \
signal_flag = exec_env->current_status->signal_flag; \
os_mutex_unlock(&exec_env->wait_lock); \
} while (0)
#endif
#endif
#if WASM_ENABLE_LABELS_AS_VALUES != 0 #if WASM_ENABLE_LABELS_AS_VALUES != 0
#define HANDLE_OP(opcode) HANDLE_##opcode: #define HANDLE_OP(opcode) HANDLE_##opcode:
@ -1410,6 +1427,10 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
/* Record the current frame_ip, so when exception occurs, \ /* Record the current frame_ip, so when exception occurs, \
debugger can know the exact opcode who caused the exception */ \ debugger can know the exact opcode who caused the exception */ \
frame_ip_orig = frame_ip; \ frame_ip_orig = frame_ip; \
/* Atomic load the exec_env's signal_flag first, and then handle \
more with lock if it is WAMR_SIG_SINGSTEP */ \
GET_SIGNAL_FLAG(); \
if (signal_flag == WAMR_SIG_SINGSTEP) { \
os_mutex_lock(&exec_env->wait_lock); \ os_mutex_lock(&exec_env->wait_lock); \
while (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \ while (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \
&& exec_env->current_status->step_count++ == 1) { \ && exec_env->current_status->step_count++ == 1) { \
@ -1418,6 +1439,7 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
wasm_cluster_thread_waiting_run(exec_env); \ wasm_cluster_thread_waiting_run(exec_env); \
} \ } \
os_mutex_unlock(&exec_env->wait_lock); \ os_mutex_unlock(&exec_env->wait_lock); \
} \
goto *handle_table[*frame_ip++]; \ goto *handle_table[*frame_ip++]; \
} while (0) } while (0)
#else #else
@ -1428,15 +1450,23 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
#define HANDLE_OP(opcode) case opcode: #define HANDLE_OP(opcode) case opcode:
#if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0 #if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0
#define HANDLE_OP_END() \ #define HANDLE_OP_END() \
/* Record the current frame_ip, so when exception occurs, \
debugger can know the exact opcode who caused the exception */ \
frame_ip_orig = frame_ip; \
/* Atomic load the exec_env's signal_flag first, and then handle \
more with lock if it is WAMR_SIG_SINGSTEP */ \
GET_SIGNAL_FLAG(); \
if (signal_flag == WAMR_SIG_SINGSTEP) { \
os_mutex_lock(&exec_env->wait_lock); \ os_mutex_lock(&exec_env->wait_lock); \
if (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \ while (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \
&& exec_env->current_status->step_count++ == 1) { \ && exec_env->current_status->step_count++ == 1) { \
exec_env->current_status->step_count = 0; \ exec_env->current_status->step_count = 0; \
SYNC_ALL_TO_FRAME(); \ SYNC_ALL_TO_FRAME(); \
wasm_cluster_thread_waiting_run(exec_env); \ wasm_cluster_thread_waiting_run(exec_env); \
} \ } \
os_mutex_unlock(&exec_env->wait_lock); \ os_mutex_unlock(&exec_env->wait_lock); \
continue } \
continue;
#else #else
#define HANDLE_OP_END() continue #define HANDLE_OP_END() continue
#endif #endif
@ -1545,6 +1575,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
debug_instance ? &debug_instance->watch_point_list_read : NULL; debug_instance ? &debug_instance->watch_point_list_read : NULL;
bh_list *watch_point_list_write = bh_list *watch_point_list_write =
debug_instance ? &debug_instance->watch_point_list_write : NULL; debug_instance ? &debug_instance->watch_point_list_write : NULL;
#if WASM_ENABLE_THREAD_MGR != 0
uint32 signal_flag;
#endif
#endif #endif
#if WASM_ENABLE_LABELS_AS_VALUES != 0 #if WASM_ENABLE_LABELS_AS_VALUES != 0

View File

@ -184,9 +184,9 @@ wasm_cluster_is_thread_terminated(WASMExecEnv *exec_env);
((signo) == WAMR_SIG_STOP || (signo) == WAMR_SIG_TRAP) ((signo) == WAMR_SIG_STOP || (signo) == WAMR_SIG_TRAP)
struct WASMCurrentEnvStatus { struct WASMCurrentEnvStatus {
uint64 signal_flag : 32; uint32 signal_flag;
uint64 step_count : 16; uint16 step_count;
uint64 running_status : 16; uint16 running_status;
}; };
WASMCurrentEnvStatus * WASMCurrentEnvStatus *