From 1a4aa5ac2f659439a344c0ec7163b157c0e190ce Mon Sep 17 00:00:00 2001 From: Wenyong Huang Date: Mon, 14 Jun 2021 08:58:32 +0800 Subject: [PATCH] Enable multi-thread for tensorflow sample, update wasm-c-api document (#651) --- .../lib-pthread/lib_pthread_wrapper.c | 33 ++++-- .../libraries/thread-mgr/thread_manager.c | 7 +- doc/pthread_library.md | 12 ++ doc/wasm_c_api.md | 110 +++++++++--------- samples/workload/tensorflow/README.md | 4 +- samples/workload/tensorflow/build.sh | 14 ++- samples/workload/tensorflow/tf_lite.patch | 8 +- 7 files changed, 115 insertions(+), 73 deletions(-) diff --git a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c index 95634834..0eaed87b 100644 --- a/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c +++ b/core/iwasm/libraries/lib-pthread/lib_pthread_wrapper.c @@ -542,24 +542,24 @@ pthread_create_wrapper(wasm_exec_env_t exec_env, uint32 thread_handle; int32 ret = -1; #if WASM_ENABLE_LIBC_WASI != 0 - WASIContext *wasi_ctx = get_wasi_ctx(module_inst); + WASIContext *wasi_ctx; #endif bh_assert(module); + bh_assert(module_inst); if (!(new_module_inst = wasm_runtime_instantiate_internal(module, true, 8192, 0, NULL, 0))) return -1; - if (module_inst) { - /* Set custom_data to new module instance */ - wasm_runtime_set_custom_data_internal( - new_module_inst, - wasm_runtime_get_custom_data(module_inst)); - } + /* Set custom_data to new module instance */ + wasm_runtime_set_custom_data_internal( + new_module_inst, + wasm_runtime_get_custom_data(module_inst)); #if WASM_ENABLE_LIBC_WASI != 0 + wasi_ctx = get_wasi_ctx(module_inst); if (wasi_ctx) wasm_runtime_set_wasi_ctx(new_module_inst, wasi_ctx); #endif @@ -628,7 +628,7 @@ pthread_join_wrapper(wasm_exec_env_t exec_env, uint32 thread, /* validate addr, we can use current thread's module instance here as the memory is shared */ - if (!validate_app_addr(retval_offset, sizeof(void *))) { + if (!validate_app_addr(retval_offset, sizeof(int32))) { /* Join failed, but we don't want to terminate all threads, do not spread exception here */ wasm_runtime_set_exception(module_inst, NULL); @@ -1046,6 +1046,22 @@ pthread_key_delete_wrapper(wasm_exec_env_t exec_env, int32 key) return 0; } +/* Currently the memory allocator doesn't support alloc specific aligned + space, we wrap posix_memalign to simply malloc memory */ +static int32 +posix_memalign_wrapper(wasm_exec_env_t exec_env, + void **memptr, int32 align, int32 size) +{ + wasm_module_inst_t module_inst = get_module_inst(exec_env); + void *p = NULL; + + *((int32 *)memptr) = module_malloc(size, (void**)&p); + if (!p) + return -1; + + return 0; +} + #define REG_NATIVE_FUNC(func_name, signature) \ { #func_name, func_name##_wrapper, signature, NULL } @@ -1069,6 +1085,7 @@ static NativeSymbol native_symbols_lib_pthread[] = { REG_NATIVE_FUNC(pthread_setspecific, "(ii)i"), REG_NATIVE_FUNC(pthread_getspecific, "(i)i"), REG_NATIVE_FUNC(pthread_key_delete, "(i)i"), + REG_NATIVE_FUNC(posix_memalign, "(*ii)i"), }; uint32 diff --git a/core/iwasm/libraries/thread-mgr/thread_manager.c b/core/iwasm/libraries/thread-mgr/thread_manager.c index 59330a84..4ee917a8 100644 --- a/core/iwasm/libraries/thread-mgr/thread_manager.c +++ b/core/iwasm/libraries/thread-mgr/thread_manager.c @@ -659,6 +659,7 @@ void wasm_cluster_spread_exception(WASMExecEnv *exec_env) { WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); traverse_list(&cluster->exec_env_list, set_exception_visitor, exec_env); } @@ -677,7 +678,11 @@ wasm_cluster_spread_custom_data(WASMModuleInstanceCommon *module_inst, void *custom_data) { WASMExecEnv *exec_env = wasm_clusters_search_exec_env(module_inst); - WASMCluster *cluster = wasm_exec_env_get_cluster(exec_env); + WASMCluster *cluster = NULL; + bh_assert(exec_env); + + cluster = wasm_exec_env_get_cluster(exec_env); + bh_assert(cluster); traverse_list(&cluster->exec_env_list, set_custom_data_visitor, diff --git a/doc/pthread_library.md b/doc/pthread_library.md index 882bb59d..b1de6b10 100644 --- a/doc/pthread_library.md +++ b/doc/pthread_library.md @@ -78,6 +78,18 @@ Then build the program with this command: # -Wl,--no-check-features: the errno.o in wasi-sysroot is not compatible with pthread feature, pass this option to avoid errors ``` +**Build with EMCC** + +EMCC's `-pthread` option is not compatible with standalone mode, we need to pass `-mbulk-memory -matomics` to the compiler and `--shared-memory,--no-check-features` to linker manually + +``` bash +emcc -O3 -mbulk-memory -matomics -s MALLOC="none" \ + -Wl,--export=__data_end,--export=__heap_base \ + -Wl,--shared-memory,--no-check-features \ + -s ERROR_ON_UNDEFINED_SYMBOLS=0 \ + main.c -o test.wasm +``` + **Build AoT module** You can build the wasm module into AoT module with pthread support, please pass option `--enable-multi-thread` to wamrc: diff --git a/doc/wasm_c_api.md b/doc/wasm_c_api.md index 6d227874..a23096e5 100644 --- a/doc/wasm_c_api.md +++ b/doc/wasm_c_api.md @@ -7,71 +7,69 @@ Every user should be familiar with *APIs* listed in all [examples][https://github.com/WebAssembly/wasm-c-api/tree/master/example] are very helpful for learning. -Currently, we support partial of *APIs* and are going to support the rest of +Currently, we support partial of APIs and are going to support the rest of them in next releases. -Supported APIs: +a summary of unsupported APIs + +- Configuration ``` c -/* wasm_bytevec_t APIs ... */ - -wasm_engine_t *wasm_engine_new(); -wasm_engine_t *wasm_engine_new_with_args(mem_alloc_type_t, const MemAllocOption*, runtime_mode_e); -void wasm_engine_delete(wasm_engine_t *); - -wasm_store_t *wasm_store_new(wasm_engine_t *); -void wasm_store_delete(wasm_store_t *); - -/* wasm_valtype_t APIs ... */ -/* wasm_valtype_vec_t APIs ... */ -/* wasm_functype_vec_t APIs ... */ -/* wasm_globaltype_vec_t APIs ... */ -/* wasm_val_t APIs ... */ -/* wasm_trap_t partial APIs ... */ - -wasm_module_t *wasm_module_new(wasm_store_t *, const wasm_byte_vec_t *); -void wasm_module_delete(wasm_module_t *); - -wasm_func_t *wasm_func_new(wasm_store_t *, const wasm_functype_t *, wasm_func_callback_t); -wasm_func_t *wasm_func_new_with_env(wasm_store_t *store, const wasm_functype_t *, wasm_func_callback_with_env_t, void *env, void (*finalizer)(void *)); -void wasm_func_delete(wasm_func_t *); -wasm_fucn_t *wasm_func_copy(const wasm_func_t *); -wasm_functype_t *wasm_func_type(const wasm_func_t *); -wasm_trap_t * wasm_func_call(const wasm_func_t *, const wasm_val_t params[], wasm_val_t results[]); -size_t wasm_func_param_arity(const wasm_func_t *); -size_t wasm_func_result_arity(const wasm_func_t *); - -wasm_global_t *wasm_global_new(wasm_store_t *, const wasm_globaltype_t *, const wasm_val_t *); -wasm_global_t * wasm_global_copy(const wasm_global_t *); -void wasm_global_delete(wasm_global_t *); -bool wasm_global_same(const wasm_global_t *, const wasm_global_t *); -void wasm_global_set(wasm_global_t *, const wasm_val_t *); -void wasm_global_get(const wasm_global_t *, wasm_val_t *out); -wasm_globaltype_t * wasm_global_type(const wasm_global_t *); - -wasm_instance_t *wasm_instance_new(wasm_store_t *, const wasm_module_t *, const wasm_extern_t *const imports[], wasm_trap_t **traps); -void wasm_instance_delete(wasm_instance_t *); -void wasm_instance_exports(const wasm_instance_t *, wasm_extern_vec_t *out); - -/* wasm_extern_t APIs */ +WASM_API_EXTERN own wasm_config_t* wasm_config_new(void); ``` -Unsupported APIs: +- References ``` c -/* wasm_tabletype_t APIs */ -/* wasm_memorytype_t APIs */ -/* wasm_externtype_t APIs */ -/* wasm_importtype_t APIs */ -/* wasm_exporttype_t APIs */ -/* wasm_ref_t APIs */ -/* wasm_shared_##name##_t APIs */ +WASM_API_EXTERN bool wasm_##name##_same(const wasm_##name##_t*, const wasm_##name##_t*); \ +WASM_API_EXTERN void* wasm_##name##_get_host_info(const wasm_##name##_t*); \ +WASM_API_EXTERN void wasm_##name##_set_host_info(wasm_##name##_t*, void*); \ +WASM_API_EXTERN void wasm_##name##_set_host_info_with_finalizer( \ +WASM_API_EXTERN wasm_ref_t* wasm_##name##_as_ref(wasm_##name##_t*); \ +WASM_API_EXTERN wasm_##name##_t* wasm_ref_as_##name(wasm_ref_t*); \ +WASM_API_EXTERN const wasm_ref_t* wasm_##name##_as_ref_const(const wasm_##name##_t*); \ +WASM_API_EXTERN const wasm_##name##_t* wasm_ref_as_##name##_const(const wasm_ref_t*); +WASM_API_EXTERN own wasm_shared_##name##_t* wasm_##name##_share(const wasm_##name##_t*); \ +WASM_API_EXTERN own wasm_##name##_t* wasm_##name##_obtain(wasm_store_t*, const wasm_shared_##name##_t*); +``` +- Frames + +``` c +WASM_API_EXTERN own wasm_frame_t* wasm_frame_copy(const wasm_frame_t*); +WASM_API_EXTERN struct wasm_instance_t* wasm_frame_instance(const wasm_frame_t*); +WASM_API_EXTERN uint32_t wasm_frame_func_index(const wasm_frame_t*); +WASM_API_EXTERN size_t wasm_frame_func_offset(const wasm_frame_t*); +WASM_API_EXTERN size_t wasm_frame_module_offset(const wasm_frame_t*); +WASM_API_EXTERN own wasm_frame_t* wasm_trap_origin(const wasm_trap_t*); +WASM_API_EXTERN void wasm_trap_trace(const wasm_trap_t*, own wasm_frame_vec_t* out); +``` + + Foreign Objects + +``` c +WASM_API_EXTERN own wasm_foreign_t* wasm_foreign_new(wasm_store_t*); +``` + +- Several Module APIs + +``` c WASM_API_EXTERN bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* binary); -WASM_API_EXTERN void wasm_module_imports(const wasm_module_t*, own wasm_importtype_vec_t* out); WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out); -WASM_API_EXTERN own wasm_module_t* wasm_module_deserialize(wasm_store_t*, const wasm_byte_vec_t*); - -/* wasm_table_t APIs */ -/* wasm_memory_t APIs */ +WASM_API_EXTERN void wasm_module_serialize(const wasm_module_t*, own wasm_byte_vec_t* out); ``` + +- Table Operations APIs + +``` c +WASM_API_EXTERN own wasm_ref_t* wasm_table_get(const wasm_table_t*, wasm_table_size_t index); +WASM_API_EXTERN bool wasm_table_set(wasm_table_t*, wasm_table_size_t index, wasm_ref_t*); +WASM_API_EXTERN wasm_table_size_t wasm_table_size(const wasm_table_t*); +WASM_API_EXTERN bool wasm_table_grow(wasm_table_t*, wasm_table_size_t delta, wasm_ref_t* init); +``` + +- Memory Grow APIs + +``` c +WASM_API_EXTERN bool wasm_memory_grow(wasm_memory_t*, wasm_memory_pages_t delta); +``` \ No newline at end of file diff --git a/samples/workload/tensorflow/README.md b/samples/workload/tensorflow/README.md index 11fa28b8..2aca871a 100644 --- a/samples/workload/tensorflow/README.md +++ b/samples/workload/tensorflow/README.md @@ -17,7 +17,9 @@ Then run ./build.sh # for linux platform, or ./build.sh --sgx -# for linux-sgx platform +# for linux-sgx platform or +./build.sh --threads +# for multi-thread execution (on linux platform) ``` to build tensorflow and run it with iwasm, which basically contains the following steps: - hack emcc to delete some objects in libc.a diff --git a/samples/workload/tensorflow/build.sh b/samples/workload/tensorflow/build.sh index 80d2540d..f3e686b7 100755 --- a/samples/workload/tensorflow/build.sh +++ b/samples/workload/tensorflow/build.sh @@ -1,10 +1,10 @@ +#!/bin/bash + # # Copyright (C) 2019 Intel Corporation. All rights reserved. # SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception # -#!/bin/bash - #################################### # build tensorflow-lite sample # #################################### @@ -99,6 +99,8 @@ WAMRC_CMD="$(pwd)/wamrc" cd ${OUT_DIR} if [[ $1 == '--sgx' ]]; then ${WAMRC_CMD} --enable-simd -sgx -o benchmark_model.aot benchmark_model.wasm +elif [[ $1 == '--threads' ]]; then + ${WAMRC_CMD} --enable-simd --enable-multi-thread -o benchmark_model.aot benchmark_model.wasm else ${WAMRC_CMD} --enable-simd -o benchmark_model.aot benchmark_model.wasm fi @@ -137,7 +139,13 @@ else IWASM_CMD="${WAMR_PLATFORM_DIR}/linux/build/iwasm" fi -${IWASM_CMD} --heap-size=10475860 \ +if [[ $1 == '--threads' ]]; then + ${IWASM_CMD} --heap-size=10475860 \ + ${OUT_DIR}/benchmark_model.aot --num_threads=4 \ + --graph=mobilenet_quant_v1_224.tflite --max_secs=300 +else + ${IWASM_CMD} --heap-size=10475860 \ ${OUT_DIR}/benchmark_model.aot \ --graph=mobilenet_quant_v1_224.tflite --max_secs=300 +fi diff --git a/samples/workload/tensorflow/tf_lite.patch b/samples/workload/tensorflow/tf_lite.patch index 4d510b1b..b6224d58 100644 --- a/samples/workload/tensorflow/tf_lite.patch +++ b/samples/workload/tensorflow/tf_lite.patch @@ -19,14 +19,14 @@ index c7ddff58440..ebfebaead35 100644 endif # ifeq ($(HOST_OS),$(TARGET)) endif -+CFLAGS+=-msimd128 -+CXXFLAGS+=-msimd128 ++CFLAGS+=-msimd128 -mbulk-memory -matomics ++CXXFLAGS+=-msimd128 -mbulk-memory -matomics + -+LIBFLAGS += -s TOTAL_STACK=1048576 \ ++LIBFLAGS += -s TOTAL_STACK=1048576 -s MALLOC="none" \ + -s INITIAL_MEMORY=16777216 \ + -s MAXIMUM_MEMORY=167772160 \ + -s ALLOW_MEMORY_GROWTH=1 \ -+ -Wl,--export=__data_end -Wl,--export=__heap_base \ ++ -Wl,--export=__data_end -Wl,--export=__heap_base,--shared-memory,--no-check-features \ + -s ERROR_ON_UNDEFINED_SYMBOLS=0 + # This library is the main target for this makefile. It will contain a minimal