Преглед изворни кода

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.
Wenyong Huang пре 1 година
родитељ
комит
da25906ed4

+ 56 - 23
core/iwasm/interpreter/wasm_interp_classic.c

@@ -1399,17 +1399,64 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
 #endif /* WASM_ENABLE_DEBUG_INTERP */
 #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
 
 #define HANDLE_OP(opcode) HANDLE_##opcode:
 #define FETCH_OPCODE_AND_DISPATCH() goto *handle_table[*frame_ip++]
 
+#if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0
+#define HANDLE_OP_END()                                                       \
+    do {                                                                      \
+        /* 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);                              \
+            while (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \
+                   && exec_env->current_status->step_count++ == 1) {          \
+                exec_env->current_status->step_count = 0;                     \
+                SYNC_ALL_TO_FRAME();                                          \
+                wasm_cluster_thread_waiting_run(exec_env);                    \
+            }                                                                 \
+            os_mutex_unlock(&exec_env->wait_lock);                            \
+        }                                                                     \
+        goto *handle_table[*frame_ip++];                                      \
+    } while (0)
+#else
+#define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH()
+#endif
+
+#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
+#define HANDLE_OP(opcode) case opcode:
 #if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0
 #define HANDLE_OP_END()                                                   \
-    do {                                                                  \
-        /* Record the current frame_ip, so when exception occurs,         \
-           debugger can know the exact opcode who caused the exception */ \
-        frame_ip_orig = frame_ip;                                         \
+    /* 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);                              \
         while (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \
                && exec_env->current_status->step_count++ == 1) {          \
@@ -1418,25 +1465,8 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst,
             wasm_cluster_thread_waiting_run(exec_env);                    \
         }                                                                 \
         os_mutex_unlock(&exec_env->wait_lock);                            \
-        goto *handle_table[*frame_ip++];                                  \
-    } while (0)
-#else
-#define HANDLE_OP_END() FETCH_OPCODE_AND_DISPATCH()
-#endif
-
-#else /* else of WASM_ENABLE_LABELS_AS_VALUES */
-#define HANDLE_OP(opcode) case opcode:
-#if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0
-#define HANDLE_OP_END()                                            \
-    os_mutex_lock(&exec_env->wait_lock);                           \
-    if (exec_env->current_status->signal_flag == WAMR_SIG_SINGSTEP \
-        && exec_env->current_status->step_count++ == 1) {          \
-        exec_env->current_status->step_count = 0;                  \
-        SYNC_ALL_TO_FRAME();                                       \
-        wasm_cluster_thread_waiting_run(exec_env);                 \
-    }                                                              \
-    os_mutex_unlock(&exec_env->wait_lock);                         \
-    continue
+    }                                                                     \
+    continue;
 #else
 #define HANDLE_OP_END() continue
 #endif
@@ -1545,6 +1575,9 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module,
         debug_instance ? &debug_instance->watch_point_list_read : NULL;
     bh_list *watch_point_list_write =
         debug_instance ? &debug_instance->watch_point_list_write : NULL;
+#if WASM_ENABLE_THREAD_MGR != 0
+    uint32 signal_flag;
+#endif
 #endif
 
 #if WASM_ENABLE_LABELS_AS_VALUES != 0

+ 3 - 3
core/iwasm/libraries/thread-mgr/thread_manager.h

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