Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 13 additions & 13 deletions .github/workflows/compilation_on_android_ubuntu_macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ env:
AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0"
LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1"
MC_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0"
LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex"

jobs:
Expand Down Expand Up @@ -193,8 +193,8 @@ jobs:
# Running mode
$CLASSIC_INTERP_BUILD_OPTIONS,
$FAST_INTERP_BUILD_OPTIONS,
$JIT_BUILD_OPTIONS,
$LAZY_JIT_BUILD_OPTIONS,
$MC_JIT_BUILD_OPTIONS,
$AOT_BUILD_OPTIONS,
]
make_options_feature: [
Expand Down Expand Up @@ -232,11 +232,11 @@ jobs:
make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
# uncompatiable mode and feature
# MULTI_MODULE only on INTERP mode
- make_options_run_mode: $JIT_BUILD_OPTIONS
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
- make_options_run_mode: $AOT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS
- make_options_run_mode: $MC_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MULTI_MODULE=1"
# SIMD only on JIT/AOT mode
- make_options_run_mode: $CLASSIC_INTERP_BUILD_OPTIONS
Expand All @@ -246,10 +246,10 @@ jobs:
# DEBUG_INTERP only on CLASSIC INTERP mode
- make_options_run_mode: $AOT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
- make_options_run_mode: $JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
- make_options_run_mode: $MC_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
- make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_INTERP=1"
# DEBUG_AOT only on JIT/AOT mode
Expand All @@ -258,17 +258,17 @@ jobs:
- make_options_run_mode: $FAST_INTERP_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
# TODO: DEBUG_AOT on JIT
- make_options_run_mode: $JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
- make_options_run_mode: $MC_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_DEBUG_AOT=1"
# MINI_LOADER only on INTERP mode
- make_options_run_mode: $AOT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
- make_options_run_mode: $JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
- make_options_run_mode: $LAZY_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
- make_options_run_mode: $MC_JIT_BUILD_OPTIONS
make_options_feature: "-DWAMR_BUILD_MINI_LOADER=1"
include:
- os: ubuntu-18.04
light: ${{ needs.check_repo.outputs.traffic_light_on_ubuntu_1804 }}
Expand Down Expand Up @@ -318,8 +318,8 @@ jobs:
# Running mode
$CLASSIC_INTERP_BUILD_OPTIONS,
$FAST_INTERP_BUILD_OPTIONS,
$JIT_BUILD_OPTIONS,
$LAZY_JIT_BUILD_OPTIONS,
$MC_JIT_BUILD_OPTIONS,
$AOT_BUILD_OPTIONS,
]
os: [ubuntu-18.04, ubuntu-20.04, macos-latest]
Expand All @@ -339,11 +339,11 @@ jobs:
exclude:
# TODO: a .aot compatiable problem
- os: macos-latest
make_options: $JIT_BUILD_OPTIONS
make_options: $LAZY_JIT_BUILD_OPTIONS
- os: macos-latest
make_options: $AOT_BUILD_OPTIONS
- os: macos-latest
make_options: $LAZY_JIT_BUILD_OPTIONS
make_options: $MC_JIT_BUILD_OPTIONS
steps:
- name: light status
run: echo "matrix.os=${{ matrix.os }}, light=${{ matrix.light }}"
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/compilation_on_sgx.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ env:
AOT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
CLASSIC_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
FAST_INTERP_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=0 -DWAMR_BUILD_FAST_INTERP=1 -DWAMR_BUILD_INTERP=1 -DWAMR_BUILD_JIT=0 -DWAMR_BUILD_LAZY_JIT=0"
JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0"
LAZY_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=1"
MC_JIT_BUILD_OPTIONS: "-DWAMR_BUILD_AOT=1 -DWAMR_BUILD_FAST_INTERP=0 -DWAMR_BUILD_INTERP=0 -DWAMR_BUILD_JIT=1 -DWAMR_BUILD_LAZY_JIT=0"
LLVM_CACHE_SUFFIX: "build-llvm_libraries_ex"

jobs:
Expand Down Expand Up @@ -116,8 +116,8 @@ jobs:
$CLASSIC_INTERP_BUILD_OPTIONS,
$FAST_INTERP_BUILD_OPTIONS,
# doesn't support
# $JIT_BUILD_OPTIONS,
# $LAZY_JIT_BUILD_OPTIONS,
# $MC_JIT_BUILD_OPTIONS,
$AOT_BUILD_OPTIONS,
]
make_options_feature: [
Expand Down Expand Up @@ -208,8 +208,8 @@ jobs:
$CLASSIC_INTERP_BUILD_OPTIONS,
$FAST_INTERP_BUILD_OPTIONS,
# doesn't support
#$JIT_BUILD_OPTIONS,
#$LAZY_JIT_BUILD_OPTIONS,
#$MC_JIT_BUILD_OPTIONS,
#$AOT_BUILD_OPTIONS,
]
os: [ubuntu-20.04]
Expand Down
9 changes: 5 additions & 4 deletions build-scripts/config_common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,9 @@ endif ()
if (WAMR_BUILD_JIT EQUAL 1)
if (WAMR_BUILD_AOT EQUAL 1)
add_definitions("-DWASM_ENABLE_JIT=1")
if (WAMR_BUILD_LAZY_JIT EQUAL 1)
if (NOT WAMR_BUILD_LAZY_JIT EQUAL 0)
# Enable Lazy JIT by default
set (WAMR_BUILD_LAZY_JIT 1)
add_definitions("-DWASM_ENABLE_LAZY_JIT=1")
endif ()
if (NOT DEFINED LLVM_DIR)
Expand Down Expand Up @@ -128,11 +130,10 @@ else ()
message (" WAMR AOT disabled")
endif ()
if (WAMR_BUILD_JIT EQUAL 1)
message (" WAMR JIT enabled")
if (WAMR_BUILD_LAZY_JIT EQUAL 1)
message (" WAMR LazyJIT enabled")
message (" WAMR Lazy JIT enabled")
else ()
message (" WAMR LazyJIT disabled")
message (" WAMR MC JIT enabled")
endif ()
else ()
message (" WAMR JIT disabled")
Expand Down
4 changes: 4 additions & 0 deletions core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@
#define WASM_ENABLE_LAZY_JIT 0
#endif

#ifndef WASM_LAZY_JIT_COMPILE_THREAD_NUM
#define WASM_LAZY_JIT_COMPILE_THREAD_NUM 4
#endif

#if (WASM_ENABLE_AOT == 0) && (WASM_ENABLE_JIT != 0)
/* LazyJIT or MCJIT can only be enabled when AOT is enabled */
#undef WASM_ENABLE_JIT
Expand Down
184 changes: 139 additions & 45 deletions core/iwasm/aot/aot_loader.c
Original file line number Diff line number Diff line change
Expand Up @@ -2760,6 +2760,90 @@ aot_load_from_aot_file(const uint8 *buf, uint32 size, char *error_buf,
}

#if WASM_ENABLE_JIT != 0
#if WASM_ENABLE_LAZY_JIT != 0
/* Orc JIT thread arguments */
typedef struct OrcJitThreadArg {
AOTCompData *comp_data;
AOTCompContext *comp_ctx;
AOTModule *module;
int32 group_idx;
int32 group_stride;
} OrcJitThreadArg;

static bool orcjit_stop_compiling = false;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

可能需要考虑用 volatile 强化线程间共享的变量

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

应该不需要加volatile吧,编译的线程在调用orc lookup编译某个函数后,读这个变量,如果变成true,就不再编译其它函数,退出线程了。即使读到的这个变量还是fasle,最坏情况就是再编译一次下一个函数吧。

static korp_tid orcjit_threads[WASM_LAZY_JIT_COMPILE_THREAD_NUM];
static OrcJitThreadArg orcjit_thread_args[WASM_LAZY_JIT_COMPILE_THREAD_NUM];

static void *
orcjit_thread_callback(void *arg)
{
LLVMErrorRef error;
LLVMOrcJITTargetAddress func_addr = 0;
OrcJitThreadArg *thread_arg = (OrcJitThreadArg *)arg;
AOTCompData *comp_data = thread_arg->comp_data;
AOTCompContext *comp_ctx = thread_arg->comp_ctx;
AOTModule *module = thread_arg->module;
char func_name[32];
int32 i;

/* Compile wasm functions of this group */
for (i = thread_arg->group_idx; i < (int32)comp_data->func_count;
i += thread_arg->group_stride) {
if (!module->func_ptrs[i]) {
snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i);
if ((error = LLVMOrcLLJITLookup(comp_ctx->orc_lazyjit, &func_addr,
func_name))) {
char *err_msg = LLVMGetErrorMessage(error);
os_printf("failed to compile orc jit function: %s", err_msg);
LLVMDisposeErrorMessage(err_msg);
break;
}
/**
* No need to lock the func_ptr[func_idx] here as it is basic
* data type, the load/store for it can be finished by one cpu
* instruction, and there can be only one cpu instruction
* loading/storing at the same time.
*/
module->func_ptrs[i] = (void *)func_addr;
}
if (orcjit_stop_compiling) {
break;
}
}

/* Try to compile functions that haven't been compiled by other threads */
for (i = (int32)comp_data->func_count - 1; i > 0; i--) {
if (orcjit_stop_compiling) {
break;
}
if (!module->func_ptrs[i]) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

L2819 和 L2792 会不会遇到多线程反复赋值的情况。比如:

  • thread A 走到L2821的位置被挂起
  • thread B 走到 L2819 发现没有赋值,又走一遍 L2821
  • 结果是 thread A 和 B 都调用了 LVMOrcLLJITLookup,然后给 func_ptrs[i] 赋值两次?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

按照LLVM的说法,LLVMOrcLLJITLookup本身支持并发操作,并且同一个wasm函数只会被编译一次,编译了之后再次lookup会返回同一个指针:

Symbol lookup in ORC serves two other important functions, beyond providing addresses for symbols: (1) It triggers compilation of the symbol(s) searched for (if they have not been compiled already), and (2) it provides the synchronization mechanism for concurrent compilation. 

这边是有可能多线程重复对一个指针赋值,但是即使重复赋值,赋的也是一样的值,另外这个应该不会有多线程读写冲突的问题,因为读写的指针类型是基本的数据类型,可以用一条机器指令完成,同一时刻只能总线上只能有一条指令在读或写一个指针。实际测试了很多case,没有发现有问题。参考:
https://www.cnblogs.com/zhouyazhou/p/7747926.html

snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i);
if ((error = LLVMOrcLLJITLookup(comp_ctx->orc_lazyjit, &func_addr,
func_name))) {
char *err_msg = LLVMGetErrorMessage(error);
os_printf("failed to compile orc jit function: %s", err_msg);
LLVMDisposeErrorMessage(err_msg);
break;
}
module->func_ptrs[i] = (void *)func_addr;
}
}

return NULL;
}

static void
orcjit_stop_compile_threads()
{
uint32 i;

orcjit_stop_compiling = true;
for (i = 0; i < WASM_LAZY_JIT_COMPILE_THREAD_NUM; i++) {
os_thread_join(orcjit_threads[i], NULL);
}
}
#endif

static AOTModule *
aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx,
char *error_buf, uint32 error_buf_size)
Expand All @@ -2769,13 +2853,6 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx,
char func_name[32];
AOTModule *module;

#if WASM_ENABLE_LAZY_JIT != 0
LLVMOrcThreadSafeModuleRef ts_module;
LLVMOrcJITDylibRef main_dylib;
LLVMErrorRef error;
LLVMOrcJITTargetAddress func_addr = 0;
#endif

/* Allocate memory for module */
if (!(module =
loader_malloc(sizeof(AOTModule), error_buf, error_buf_size))) {
Expand Down Expand Up @@ -2839,44 +2916,28 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx,
}

#if WASM_ENABLE_LAZY_JIT != 0
bh_assert(comp_ctx->lazy_orcjit);

main_dylib = LLVMOrcLLLazyJITGetMainJITDylib(comp_ctx->lazy_orcjit);
if (!main_dylib) {
set_error_buf(error_buf, error_buf_size,
"failed to get dynmaic library reference");
goto fail3;
}
/* Create threads to compile the wasm functions */
for (i = 0; i < WASM_LAZY_JIT_COMPILE_THREAD_NUM; i++) {
orcjit_thread_args[i].comp_data = comp_data;
orcjit_thread_args[i].comp_ctx = comp_ctx;
orcjit_thread_args[i].module = module;
orcjit_thread_args[i].group_idx = (int32)i;
orcjit_thread_args[i].group_stride = WASM_LAZY_JIT_COMPILE_THREAD_NUM;
if (os_thread_create(&orcjit_threads[i], orcjit_thread_callback,
(void *)&orcjit_thread_args[i],
APP_THREAD_STACK_SIZE_DEFAULT)
!= 0) {
uint32 j;

ts_module = LLVMOrcCreateNewThreadSafeModule(comp_ctx->module,
comp_ctx->ts_context);
if (!ts_module) {
set_error_buf(error_buf, error_buf_size,
"failed to create thread safe module");
goto fail3;
}

if ((error = LLVMOrcLLLazyJITAddLLVMIRModule(comp_ctx->lazy_orcjit,
main_dylib, ts_module))) {
/*
* If adding the ThreadSafeModule fails then we need to clean it up
* ourselves. If adding it succeeds the JIT will manage the memory.
*/
aot_handle_llvm_errmsg(error_buf, error_buf_size,
"failed to addIRModule: ", error);
goto fail4;
}

for (i = 0; i < comp_data->func_count; i++) {
snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX, i);
if ((error = LLVMOrcLLLazyJITLookup(comp_ctx->lazy_orcjit, &func_addr,
func_name))) {
aot_handle_llvm_errmsg(error_buf, error_buf_size,
"cannot lookup: ", error);
set_error_buf(error_buf, error_buf_size,
"create orcjit compile thread failed");
/* Terminate the threads created */
orcjit_stop_compiling = true;
for (j = 0; j < i; j++) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

是否要考虑把 os_thread_join 的循环拿到外面?减少反复 join 的次数?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这边是当创建线程失败时,去join其它已经创建的线程,不会反复join。移到外面的话,就要join所有线程,相当于等所有线程都编译好再执行,就不是真正的lazy编译了。这边创建了这些线程让它们进行编译,同时主线程还接着往前走调用jit函数,主线程一旦发现有函数没有编译,也会orc lookup编译一下。

os_thread_join(orcjit_threads[j], NULL);
}
goto fail3;
}
module->func_ptrs[i] = (void *)func_addr;
func_addr = 0;
}
#else
/* Resolve function addresses */
Expand All @@ -2897,7 +2958,7 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx,
if (size > 0
&& !(module->func_type_indexes =
loader_malloc(size, error_buf, error_buf_size))) {
goto fail3;
goto fail4;
}
for (i = 0; i < comp_data->func_count; i++)
module->func_type_indexes[i] = comp_data->funcs[i]->func_type_index;
Expand All @@ -2911,6 +2972,29 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx,
< module->import_func_count + module->func_count);
/* TODO: fix issue that start func cannot be import func */
if (comp_data->start_func_index >= module->import_func_count) {
#if WASM_ENABLE_LAZY_JIT != 0
if (!module->func_ptrs[comp_data->start_func_index
- module->import_func_count]) {
LLVMErrorRef error;
LLVMOrcJITTargetAddress func_addr = 0;

snprintf(func_name, sizeof(func_name), "%s%d", AOT_FUNC_PREFIX,
comp_data->start_func_index
- module->import_func_count);
if ((error = LLVMOrcLLJITLookup(comp_ctx->orc_lazyjit,
&func_addr, func_name))) {
char *err_msg = LLVMGetErrorMessage(error);
set_error_buf_v(error_buf, error_buf_size,
"failed to compile orc jit function: %s",
err_msg);
LLVMDisposeErrorMessage(err_msg);
goto fail5;
}
module->func_ptrs[comp_data->start_func_index
- module->import_func_count] =
(void *)func_addr;
}
#endif
module->start_function =
module->func_ptrs[comp_data->start_func_index
- module->import_func_count];
Expand Down Expand Up @@ -2945,10 +3029,16 @@ aot_load_from_comp_data(AOTCompData *comp_data, AOTCompContext *comp_ctx,
return module;

#if WASM_ENABLE_LAZY_JIT != 0
fail4:
LLVMOrcDisposeThreadSafeModule(ts_module);
fail5:
if (module->func_type_indexes)
wasm_runtime_free(module->func_type_indexes);
#endif

fail4:
#if WASM_ENABLE_LAZY_JIT != 0
/* Terminate all threads before free module->func_ptrs */
orcjit_stop_compile_threads();
#endif
fail3:
if (module->func_ptrs)
wasm_runtime_free(module->func_ptrs);
Expand Down Expand Up @@ -3034,6 +3124,10 @@ void
aot_unload(AOTModule *module)
{
#if WASM_ENABLE_JIT != 0
#if WASM_ENABLE_LAZY_JIT != 0
orcjit_stop_compile_threads();
#endif

if (module->comp_data)
aot_destroy_comp_data(module->comp_data);

Expand Down
Loading