diff --git a/build-scripts/runtime_lib.cmake b/build-scripts/runtime_lib.cmake index 3ab0cff4..5d6c25c4 100644 --- a/build-scripts/runtime_lib.cmake +++ b/build-scripts/runtime_lib.cmake @@ -130,6 +130,11 @@ if (WAMR_BUILD_DEBUG_INTERP EQUAL 1) endif () endif () +set (WAMR_BUILD_MIGRATION 1) +if (WAMR_BUILD_MIGRATION EQUAL 1) + include (${IWASM_DIR}/migration/migration.cmake) +endif() + if (WAMR_BUILD_THREAD_MGR EQUAL 1) include (${IWASM_DIR}/libraries/thread-mgr/thread_mgr.cmake) endif () @@ -193,6 +198,7 @@ set (source_all ${LIBC_EMCC_SOURCE} ${LIB_RATS_SOURCE} ${DEBUG_ENGINE_SOURCE} + ${MIGRATION_SOURCE} ) set (WAMR_RUNTIME_LIB_SOURCE ${source_all}) diff --git a/core/iwasm/common/wasm_runtime_common.c b/core/iwasm/common/wasm_runtime_common.c index f18cd784..624ebcb4 100644 --- a/core/iwasm/common/wasm_runtime_common.c +++ b/core/iwasm/common/wasm_runtime_common.c @@ -38,6 +38,7 @@ #include "../compilation/aot_llvm.h" #endif #include "../common/wasm_c_api_internal.h" +#include "../migration/wasm_restore.h" #include "../../version.h" /** @@ -777,6 +778,10 @@ wasm_runtime_full_init_internal(RuntimeInitArgs *init_args) return false; } + if (init_args->restore_flag) { + set_restore_flag(true); + } + #if WASM_ENABLE_THREAD_MGR != 0 wasm_cluster_set_max_thread_num(init_args->max_thread_num); #endif diff --git a/core/iwasm/include/wasm_export.h b/core/iwasm/include/wasm_export.h index 85fd522d..fdce0d80 100644 --- a/core/iwasm/include/wasm_export.h +++ b/core/iwasm/include/wasm_export.h @@ -218,6 +218,8 @@ typedef struct RuntimeInitArgs { uint32_t llvm_jit_size_level; /* Segue optimization flags for LLVM JIT */ uint32_t segue_flags; + /* Restore from interp.img and frame.img */ + bool restore_flag; /** * If enabled * - llvm-jit will output a jitdump file for `perf inject` diff --git a/core/iwasm/interpreter/wasm_interp_classic.c b/core/iwasm/interpreter/wasm_interp_classic.c index f7193c95..84952db8 100644 --- a/core/iwasm/interpreter/wasm_interp_classic.c +++ b/core/iwasm/interpreter/wasm_interp_classic.c @@ -3,6 +3,8 @@ * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ +#include + #include "wasm_interp.h" #include "bh_log.h" #include "wasm_runtime.h" @@ -10,6 +12,8 @@ #include "wasm_loader.h" #include "wasm_memory.h" #include "../common/wasm_exec_env.h" +#include "../migration/wasm_dump.h" +#include "../migration/wasm_restore.h" #if WASM_ENABLE_GC != 0 #include "../common/gc/gc_object.h" #include "mem_alloc.h" @@ -1396,7 +1400,18 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, #if WASM_ENABLE_LABELS_AS_VALUES != 0 #define HANDLE_OP(opcode) HANDLE_##opcode: -#define FETCH_OPCODE_AND_DISPATCH() goto *handle_table[*frame_ip++] + +#define CHECK_DUMP() \ + if (sig_flag) { \ + goto migration_async; \ + } + +// #define FETCH_OPCODE_AND_DISPATCH() goto *handle_table[*frame_ip++] +#define FETCH_OPCODE_AND_DISPATCH() \ +do { \ + CHECK_DUMP() \ + goto *handle_table[*frame_ip++]; \ +} while(0); #if WASM_ENABLE_THREAD_MGR != 0 && WASM_ENABLE_DEBUG_INTERP != 0 #define HANDLE_OP_END() \ @@ -1412,6 +1427,7 @@ wasm_interp_call_func_import(WASMModuleInstance *module_inst, wasm_cluster_thread_waiting_run(exec_env); \ } \ os_mutex_unlock(&exec_env->wait_lock); \ + CHECK_DUMP(); \ goto *handle_table[*frame_ip++]; \ } while (0) #else @@ -1450,6 +1466,26 @@ get_global_addr(uint8 *global_data, WASMGlobalInstance *global) #endif } +static void clear_refs() { + int fd; + char *v = "4"; + + fd = open("/proc/self/clear_refs", O_WRONLY); + if (write(fd, v, 3) < 3) { + perror("Can't clear soft-dirty bit"); + } + close(fd); +} + +static bool sig_flag = false; +static void (*native_handler)(void) = NULL; +bool done_flag = false; +void +wasm_interp_sigint(int signum) +{ + sig_flag = true; +} + static void wasm_interp_call_func_bytecode(WASMModuleInstance *module, WASMExecEnv *exec_env, @@ -1547,11 +1583,84 @@ wasm_interp_call_func_bytecode(WASMModuleInstance *module, #undef HANDLE_OPCODE #endif + signal(SIGINT, &wasm_interp_sigint); + // Clear soft-dirty bit + clear_refs(); + + // リストアの初期化時間の計測(終了) + struct timespec ts1; + clock_gettime(CLOCK_MONOTONIC, &ts1); + fprintf(stderr, "boot_end, %lu\n", (uint64_t)(ts1.tv_sec*1e9) + ts1.tv_nsec); + + if (get_restore_flag()) { + // bool done_flag; + int rc; + struct timespec ts1, ts2; + + clock_gettime(CLOCK_MONOTONIC, &ts1); + frame = wasm_restore_stack(&exec_env); + clock_gettime(CLOCK_MONOTONIC, &ts2); + fprintf(stderr, "stack, %lu\n", get_time(ts1, ts2)); + if (frame == NULL) { + perror("Error:wasm_interp_func_bytecode:frame is NULL\n"); + return; + } + // debug_wasm_interp_frame(frame, module->e->functions); + + cur_func = frame->function; + prev_frame = frame->prev_frame; + if (cur_func == NULL) { + perror("Error:wasm_interp_func_bytecode:cur_func is null\n"); + return; + } + if (prev_frame == NULL) { + perror("Error:wasm_interp_func_bytecode:prev_frame is null\n"); + return; + } + + uint8 *dummy_ip, *dummy_lp, *dummy_sp; + rc = wasm_restore(&module, &exec_env, &cur_func, &prev_frame, + &memory, &globals, &global_data, &global_addr, + &frame, &dummy_ip, &dummy_lp, &dummy_sp, &frame_csp, + &frame_ip_end, &else_addr, &end_addr, &maddr, &done_flag); + if (rc < 0) { + // error + perror("failed to restore\n"); + return; + } + frame_ip = dummy_ip; + frame_lp = dummy_lp; + frame_sp = dummy_sp; + frame->ip = frame_ip; + linear_mem_size = memory ? memory->memory_data_size : 0; + + frame_lp = frame->lp; + UPDATE_ALL_FROM_FRAME(); + FETCH_OPCODE_AND_DISPATCH(); + } + #if WASM_ENABLE_LABELS_AS_VALUES == 0 while (frame_ip < frame_ip_end) { opcode = *frame_ip++; switch (opcode) { #else +migration_async: + if (sig_flag) { + SYNC_ALL_TO_FRAME(); + uint8 *dummy_ip, *dummy_sp; + dummy_ip = frame_ip; + dummy_sp = frame_sp; + int rc = wasm_dump(exec_env, module, memory, + globals, global_data, global_addr, cur_func, + frame, dummy_ip, dummy_sp, frame_csp, + frame_ip_end, else_addr, end_addr, maddr, done_flag); + if (rc < 0) { + perror("failed to dump\n"); + exit(1); + } + LOG_DEBUG("dispatch_count: %d\n", dispatch_count); + exit(0); + } FETCH_OPCODE_AND_DISPATCH(); #endif /* control instructions */ diff --git a/core/iwasm/migration/migration.cmake b/core/iwasm/migration/migration.cmake new file mode 100644 index 00000000..358dcfdd --- /dev/null +++ b/core/iwasm/migration/migration.cmake @@ -0,0 +1,9 @@ +set (MIGRATION_DIR ${CMAKE_CURRENT_LIST_DIR}) + +add_definitions (-DWASM_ENABLE_MIGRATION=1) + +include_directories(${MIGRATION_DIR}) + +file (GLOB source_all ${MIGRATION_DIR}/*.c) + +set (MIGRATION_SOURCE ${source_all}) \ No newline at end of file diff --git a/core/iwasm/migration/wasm_dispatch.c b/core/iwasm/migration/wasm_dispatch.c new file mode 100644 index 00000000..a64d3139 --- /dev/null +++ b/core/iwasm/migration/wasm_dispatch.c @@ -0,0 +1,164 @@ +#include +#include + +#include "../interpreter/wasm_runtime.h" +#include "../interpreter/wasm_opcode.h" +#include "wasm_dispatch.h" + +static uint64 +read_leb(const uint8 *buf, uint32 *p_offset, uint32 maxbits, bool sign) +{ + uint64 result = 0, byte; + uint32 offset = *p_offset; + uint32 shift = 0; + + while (true) { + byte = buf[offset++]; + result |= ((byte & 0x7f) << shift); + shift += 7; + if ((byte & 0x80) == 0) { + break; + } + } + if (sign && (shift < maxbits) && (byte & 0x40)) { + /* Sign extend */ + result |= (~((uint64)0)) << shift; + } + *p_offset = offset; + return result; +} + +#define read_leb_uint32(p, p_end, res) \ + do { \ + uint8 _val = *p; \ + if (!(_val & 0x80)) { \ + res = _val; \ + p++; \ + break; \ + } \ + uint32 _off = 0; \ + res = (uint32)read_leb(p, &_off, 32, false); \ + p += _off; \ + } while (0) + +#define skip_leb(p) while (*p++ & 0x80) + +// *ipにopcodeが入ってる状態で引数に渡す +uint8* dispatch(uint8 *ip, uint8 *ip_end) { + uint32 lidx; + switch (*ip++) { + case WASM_OP_CALL_INDIRECT: + case WASM_OP_RETURN_CALL_INDIRECT: + skip_leb(ip); + skip_leb(ip); + break; + case WASM_OP_BR_TABLE: + read_leb_uint32(ip, ip_end, lidx); + for (uint32 i = 0; i < lidx; i++) + skip_leb(ip); + skip_leb(ip); + break; + /* control instructions */ + case EXT_OP_BLOCK: + case WASM_OP_BLOCK: + case EXT_OP_LOOP: + case WASM_OP_LOOP: + case EXT_OP_IF: + case WASM_OP_IF: + case WASM_OP_BR: + case WASM_OP_BR_IF: + case WASM_OP_CALL: + case WASM_OP_RETURN_CALL: +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_OP_SELECT_T: + case WASM_OP_TABLE_GET: + case WASM_OP_TABLE_SET: + case WASM_OP_REF_NULL: + case WASM_OP_REF_FUNC: +#endif + /* variable instructions */ + case WASM_OP_GET_LOCAL: + case WASM_OP_SET_LOCAL: + case WASM_OP_TEE_LOCAL: + case WASM_OP_GET_GLOBAL: + case WASM_OP_GET_GLOBAL_64: + case WASM_OP_SET_GLOBAL: + case WASM_OP_SET_GLOBAL_AUX_STACK: + case WASM_OP_SET_GLOBAL_64: + skip_leb(ip); + break; + case EXT_OP_GET_LOCAL_FAST: + case EXT_OP_SET_LOCAL_FAST: + case EXT_OP_TEE_LOCAL_FAST: + ip++; + break; + /* memory load instructions */ + case WASM_OP_I32_LOAD: + case WASM_OP_F32_LOAD: + case WASM_OP_I64_LOAD: + case WASM_OP_F64_LOAD: + case WASM_OP_I32_LOAD8_S: + case WASM_OP_I32_LOAD8_U: + case WASM_OP_I32_LOAD16_S: + case WASM_OP_I32_LOAD16_U: + case WASM_OP_I64_LOAD8_S: + case WASM_OP_I64_LOAD8_U: + case WASM_OP_I64_LOAD16_S: + case WASM_OP_I64_LOAD16_U: + case WASM_OP_I64_LOAD32_S: + case WASM_OP_I64_LOAD32_U: + case WASM_OP_I32_STORE: + case WASM_OP_F32_STORE: + case WASM_OP_I64_STORE: + case WASM_OP_F64_STORE: + case WASM_OP_I32_STORE8: + case WASM_OP_I32_STORE16: + case WASM_OP_I64_STORE8: + case WASM_OP_I64_STORE16: + case WASM_OP_I64_STORE32: + case WASM_OP_MEMORY_SIZE: + case WASM_OP_MEMORY_GROW: + skip_leb(ip); + skip_leb(ip); + break; + /* constant instructions */ + case WASM_OP_I32_CONST: + case WASM_OP_I64_CONST: + skip_leb(ip); + break; + case WASM_OP_F32_CONST: + ip += sizeof(float32); + break; + case WASM_OP_F64_CONST: + ip += sizeof(float64); + break; + case WASM_OP_MISC_PREFIX: + skip_leb(ip); + switch (*ip++) { +#if WASM_ENABLE_BULK_MEMORY != 0 + case WASM_OP_MEMORY_INIT: + case WASM_OP_DATA_DROP: + case WASM_OP_MEMORY_COPY: + case WASM_OP_MEMORY_FILL: +#endif /* WASM_ENABLE_BULK_MEMORY */ +#if WASM_ENABLE_REF_TYPES != 0 + case WASM_OP_TABLE_INIT: + case WASM_OP_ELEM_DROP: + case WASM_OP_TABLE_COPY: + case WASM_OP_TABLE_GROW: + case WASM_OP_TABLE_SIZE: + case WASM_OP_TABLE_FILL: +#endif /* WASM_ENABLE_REF_TYPES */ + skip_leb(ip); + default: + break; + } + + case WASM_OP_ATOMIC_PREFIX: + /* TODO */ + break; + default: + break; + } + return ip; +} \ No newline at end of file diff --git a/core/iwasm/migration/wasm_dispatch.h b/core/iwasm/migration/wasm_dispatch.h new file mode 100644 index 00000000..b374d4e3 --- /dev/null +++ b/core/iwasm/migration/wasm_dispatch.h @@ -0,0 +1,2 @@ +#include "../interpreter/wasm_runtime.h" +uint8* dispatch(uint8 *ip, uint8 *ip_end); \ No newline at end of file diff --git a/core/iwasm/migration/wasm_dump.c b/core/iwasm/migration/wasm_dump.c new file mode 100644 index 00000000..bdc349bb --- /dev/null +++ b/core/iwasm/migration/wasm_dump.c @@ -0,0 +1,486 @@ +#include +#include +#include + +#include "../interpreter/wasm_runtime.h" +#include "wasm_migration.h" +#include "wasm_dump.h" +#include "wasm_dispatch.h" + +// #define skip_leb(p) while (*p++ & 0x80) +#define skip_leb(p) \ + while (1) { \ + if (*p & 0x80)p++; \ + else break; \ + } \ + +int64_t get_time(struct timespec ts1, struct timespec ts2) { + int64_t sec = ts2.tv_sec - ts1.tv_sec; + int64_t nsec = ts2.tv_nsec - ts1.tv_nsec; + // std::cerr << sec << ", " << nsec << std::endl; + return sec * 1e9 + nsec; +} + +/* common_functions */ +int dump_value(void *ptr, size_t size, size_t nmemb, FILE *stream) { + if (stream == NULL) { + return -1; + } + return fwrite(ptr, size, nmemb, stream); +} + +int debug_memories(WASMModuleInstance *module) { + printf("=== debug memories ===\n"); + printf("memory_count: %d\n", module->memory_count); + + // bytes_per_page + for (int i = 0; i < module->memory_count; i++) { + WASMMemoryInstance *memory = (WASMMemoryInstance *)(module->memories[i]); + printf("%d) bytes_per_page: %d\n", i, memory->num_bytes_per_page); + printf("%d) cur_page_count: %d\n", i, memory->cur_page_count); + printf("%d) max_page_count: %d\n", i, memory->max_page_count); + printf("\n"); + } + + printf("=== debug memories ===\n"); +} + +// 積まれてるframe stackを出力する +void debug_frame_info(WASMExecEnv* exec_env, WASMInterpFrame *frame) { + WASMModuleInstance *module = exec_env->module_inst; + + int cnt = 0; + printf("=== DEBUG Frame Stack ===\n"); + do { + cnt++; + if (frame->function == NULL) { + printf("%d) func_idx: -1\n", cnt); + } + else { + printf("%d) func_idx: %d\n", cnt, frame->function - module->e->functions); + } + } while (frame = frame->prev_frame); + printf("=== DEBUG Frame Stack ===\n"); +} + +// func_instの先頭からlimitまでのopcodeを出力する +int debug_function_opcodes(WASMModuleInstance *module, WASMFunctionInstance* func, uint32 limit) { + FILE *fp = fopen("wamr_opcode.log", "a"); + if (fp == NULL) return -1; + + fprintf(fp, "fidx: %d\n", func - module->e->functions); + uint8 *ip = wasm_get_func_code(func); + uint8 *ip_end = wasm_get_func_code_end(func); + + for (int i = 0; i < limit; i++) { + fprintf(fp, "%d) opcode: 0x%x\n", i+1, *ip); + ip = dispatch(ip, ip_end); + if (ip >= ip_end) break; + } + + fclose(fp); + return 0; +} + +// int debug_flag = 0; +// ipからip_limまでにopcodeがいくつかるかを返す +int get_opcode_offset(uint8 *ip, uint8 *ip_lim) { + uint32 cnt = 0; + bh_assert(ip != NULL); + bh_assert(ip_lim != NULL); + bh_assert(ip <= ip_lim); + if (ip > ip_lim) return -1; + if (ip == ip_lim) return 0; + while (1) { + // LOG_DEBUG("get_opcode_offset::ip: 0x%x\n", *ip); + // if (debug_flag) { + // printf("(cnt, opcode) = (%d, 0x%x)\n", cnt, *ip); + // } + ip = dispatch(ip, ip_lim); + cnt++; + if (ip >= ip_lim) break; + } + return cnt; +} + +// TODO: コードごちゃごちゃで読めないので、整理する +uint8* get_type_stack(uint32 fidx, uint32 offset, uint32* type_stack_size, bool is_return_address) { + FILE *tablemap_func = fopen("tablemap_func", "rb"); + if (!tablemap_func) printf("not found tablemap_func\n"); + FILE *tablemap_offset = fopen("tablemap_offset", "rb"); + if (!tablemap_func) printf("not found tablemap_offset\n"); + FILE *type_table = fopen("type_table", "rb"); + if (!tablemap_func) printf("not found type_table\n"); + + /// tablemap_func + fseek(tablemap_func, fidx*sizeof(uint32)*3, SEEK_SET); + uint32 ffidx; + uint64 tablemap_offset_addr; + fread(&ffidx, sizeof(uint32), 1, tablemap_func); + if (fidx != ffidx) { + perror("tablemap_funcがおかしい\n"); + exit(1); + } + fread(&tablemap_offset_addr, sizeof(uint64), 1, tablemap_func); + + /// tablemap_offset + fseek(tablemap_offset, tablemap_offset_addr, SEEK_SET); + // 関数fidxのローカルを取得 + uint32 locals_size; + fread(&locals_size, sizeof(uint32), 1, tablemap_offset); + uint8 locals[locals_size]; + fread(locals, sizeof(uint8), locals_size, tablemap_offset); + // 対応するoffsetまで移動 + uint32 ooffset; + uint64 type_table_addr, pre_type_table_addr; + while(!feof(tablemap_offset)) { + fread(&ooffset, sizeof(uint32), 1, tablemap_offset); + fread(&type_table_addr, sizeof(uint64), 1, tablemap_offset); + if (offset == ooffset) break; + pre_type_table_addr = type_table_addr; + } + if (feof(tablemap_offset)) { + perror("tablemap_offsetがおかしい\n"); + exit(1); + } + // type_table_addr = pre_type_table_addr; + + /// type_table + fseek(type_table, type_table_addr, SEEK_SET); + uint32 stack_size; + fread(&stack_size, sizeof(uint32), 1, type_table); + uint8 stack[stack_size]; + fread(stack, sizeof(uint8), stack_size, type_table); + + if (is_return_address) { + fread(&stack_size, sizeof(uint32), 1, type_table); + fread(stack, sizeof(uint8), stack_size, type_table); + } + + // uint8 type_stack[locals_size + stack_size]; + uint8* type_stack = malloc(locals_size + stack_size); + for (uint32 i = 0; i < locals_size; ++i) type_stack[i] = locals[i]; + for (uint32 i = 0; i < stack_size; ++i) type_stack[locals_size + i] = stack[i]; + + // printf("new type stack: ["); + // for (uint32 i = 0; i < locals_size + stack_size; ++i) { + // if (i+1 == locals_size + stack_size)printf("%d", type_stack[i]); + // else printf("%d, ", type_stack[i]); + // } + // printf("]\n"); + + fclose(tablemap_func); + fclose(tablemap_offset); + fclose(type_table); + + *type_stack_size = locals_size + stack_size; + return type_stack; +} + +/* wasm_dump */ +static void +_dump_stack(WASMExecEnv *exec_env, struct WASMInterpFrame *frame, struct FILE *fp, bool is_top) +{ + int i; + WASMModuleInstance *module = exec_env->module_inst; + + // Entry function + // wasm_dump_stackの方でdump + + // リターンアドレス + // NOTE: 1番下のframeのときだけ、prev_frameではなくframeのリターンアドレスを出力する + WASMInterpFrame* prev_frame = (frame->prev_frame->function ? frame->prev_frame : frame); + uint32 fidx = prev_frame->function - module->e->functions; + uint32 offset = prev_frame->ip - wasm_get_func_code(prev_frame->function); + fwrite(&fidx, sizeof(uint32), 1, fp); + fwrite(&offset, sizeof(uint32), 1, fp); + + // 型スタックのサイズ + WASMFunctionInstance *func = frame->function; + uint32 locals = func->param_count + func->local_count; + // uint32 type_stack_size = (frame->tsp - frame->tsp_bottom); + // uint32 full_type_stack_size = type_stack_size + locals; + // fwrite(&full_type_stack_size, sizeof(uint32), 1, fp); + + // 型スタックの中身 + uint32 type_stack_size_from_file; + uint32 fidx_now = frame->function - module->e->functions; + uint32 offset_now = frame->ip - wasm_get_func_code(frame->function); + // printf("[DEBUG]now addr: (%d, %d)\n", fidx_now, offset_now); + uint8* type_stack_from_file = get_type_stack(fidx_now, offset_now, &type_stack_size_from_file, !is_top); + fwrite(&type_stack_size_from_file, sizeof(uint32), 1, fp); + fwrite(type_stack_from_file, sizeof(uint8), type_stack_size_from_file, fp); + free(type_stack_from_file); + + // 値スタックの中身 + uint32 local_cell_num = func->param_cell_num + func->local_cell_num; + uint32 value_stack_size = frame->sp - frame->sp_bottom; + fwrite(frame->lp, sizeof(uint32), local_cell_num, fp); + fwrite(frame->sp_bottom, sizeof(uint32), value_stack_size, fp); + + // ラベルスタックのサイズ + uint32 ctrl_stack_size = frame->csp - frame->csp_bottom; + fwrite(&ctrl_stack_size, sizeof(uint32), 1, fp); + + // ラベルスタックの中身 + WASMBranchBlock *csp = frame->csp_bottom; + uint32 addr; + uint8* ip_start = wasm_get_func_code(frame->function); + for (i = 0; i < ctrl_stack_size; ++i, ++csp) { + // uint8 *begin_addr; + addr = get_addr_offset(csp->begin_addr, ip_start); + fwrite(&addr, sizeof(uint32), 1, fp); + + // uint8 *target_addr; + addr = get_addr_offset(csp->target_addr, ip_start); + fwrite(&addr, sizeof(uint32), 1, fp); + + // uint32 *frame_sp; + addr = get_addr_offset(csp->frame_sp, frame->sp_bottom); + fwrite(&addr, sizeof(uint32), 1, fp); + + // uint32 *frame_tsp; + // addr = get_addr_offset(csp->frame_tsp, frame->tsp_bottom); + // fwrite(&addr, sizeof(uint32), 1, fp); + + // uint32 cell_num; + fwrite(&csp->cell_num, sizeof(uint32), 1, fp); + + // uint32 count; + // fwrite(&csp->count, sizeof(uint32), 1, fp); + } +} + + +int +wasm_dump_stack(WASMExecEnv *exec_env, struct WASMInterpFrame *frame) +{ + WASMModuleInstance *module = + (WASMModuleInstance *)exec_env->module_inst; + + // frameをtopからbottomまで走査する + char file[32]; + int i = 0; + do { + // dummy framenならbreak + if (frame->function == NULL) break; + + ++i; + sprintf(file, "stack%d.img", i); + FILE *fp = open_image(file, "wb"); + + uint32 entry_fidx = frame->function - module->e->functions; + fwrite(&entry_fidx, sizeof(uint32), 1, fp); + + _dump_stack(exec_env, frame, fp, (i==1)); + fclose(fp); + } while(frame = frame->prev_frame); + + // frame stackのサイズを保存 + FILE *fp = open_image("frame.img", "wb"); + fwrite(&i, sizeof(uint32), 1, fp); + fclose(fp); + + return 0; +} + +int is_dirty(uint64 pagemap_entry) { + return (pagemap_entry>>62&1) | (pagemap_entry>>63&1); +} + +int is_soft_dirty(uint64 pagemap_entry) { + return (pagemap_entry >> 55 & 1); +} + +int dump_dirty_memory(WASMMemoryInstance *memory) { + const int PAGEMAP_LENGTH = 8; + const int PAGE_SIZE = 4096; + FILE *memory_fp = open_image("memory.img", "wb"); + int fd; + uint64 pagemap_entry; + // プロセスのpagemapを開く + fd = open("/proc/self/pagemap", O_RDONLY); + if (fd == -1) { + perror("Error opening pagemap"); + return -1; + } + + // pfnに対応するpagemapエントリを取得 + unsigned long pfn = (unsigned long)memory->memory_data / PAGE_SIZE; + off_t offset = sizeof(uint64) * pfn; + if (lseek(fd, offset, SEEK_SET) == -1) { + perror("Error seeking to pagemap entry"); + close(fd); + return -1; + } + + uint8* memory_data = memory->memory_data; + uint8* memory_data_end = memory->memory_data_end; + int i = 0; + for (uint8* addr = memory->memory_data; addr < memory_data_end; addr += PAGE_SIZE, ++i) { + unsigned long pfn = (unsigned long)addr / PAGE_SIZE; + off_t offset = sizeof(uint64) * pfn; + if (lseek(fd, offset, SEEK_SET) == -1) { + perror("Error seeking to pagemap entry"); + close(fd); + return -1; + } + + if (read(fd, &pagemap_entry, PAGEMAP_LENGTH) != PAGEMAP_LENGTH) { + perror("Error reading pagemap entry"); + close(fd); + return -1; + } + + // dirty pageのみdump + // if (is_dirty(pagemap_entry)) { + if (is_soft_dirty(pagemap_entry)) { + // printf("[%x, %x]: dirty page\n", i*PAGE_SIZE, (i+1)*PAGE_SIZE); + uint32 offset = (uint64)addr - (uint64)memory_data; + // printf("i: %d\n", offset); + fwrite(&offset, sizeof(uint32), 1, memory_fp); + fwrite(addr, PAGE_SIZE, 1, memory_fp); + } + } + + close(fd); + fclose(memory_fp); + return 0; +} + +int wasm_dump_memory(WASMMemoryInstance *memory) { + FILE *mem_size_fp = open_image("mem_page_count.img", "wb"); + + dump_dirty_memory(memory); + + + printf("page_count: %d\n", memory->cur_page_count); + fwrite(&(memory->cur_page_count), sizeof(uint32), 1, mem_size_fp); + + fclose(mem_size_fp); + + // デバッグのために、すべてのメモリも保存 + // FILE *all_memory_fp = open_image("all_memory.img", "wb"); + // fwrite(memory->memory_data, sizeof(uint8), + // memory->num_bytes_per_page * memory->cur_page_count, all_memory_fp); + // fclose(all_memory_fp); +} + +int wasm_dump_global(WASMModuleInstance *module, WASMGlobalInstance *globals, uint8* global_data) { + FILE *fp; + const char *file = "global.img"; + fp = fopen(file, "wb"); + if (fp == NULL) { + fprintf(stderr, "failed to open %s\n", file); + return -1; + } + + // WASMMemoryInstance *memory = module->default_memory; + uint8 *global_addr; + for (int i = 0; i < module->e->global_count; i++) { + switch (globals[i].type) { + case VALUE_TYPE_I32: + case VALUE_TYPE_F32: + global_addr = get_global_addr_for_migration(global_data, (globals+i)); + fwrite(global_addr, sizeof(uint32), 1, fp); + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + global_addr = get_global_addr_for_migration(global_data, (globals+i)); + fwrite(global_addr, sizeof(uint64), 1, fp); + break; + default: + printf("type error:B\n"); + break; + } + } + + fclose(fp); + return 0; +} + +int wasm_dump_program_counter( + WASMModuleInstance *module, + WASMFunctionInstance *func, + uint8 *frame_ip +) +{ + FILE *fp; + const char *file = "program_counter.img"; + fp = fopen(file, "wb"); + if (fp == NULL) { + fprintf(stderr, "failed to open %s\n", file); + return -1; + } + + uint32 fidx, p_offset; + fidx = func - module->e->functions; + p_offset = frame_ip - wasm_get_func_code(func); + + dump_value(&fidx, sizeof(uint32), 1, fp); + dump_value(&p_offset, sizeof(uint32), 1, fp); +} + +int wasm_dump(WASMExecEnv *exec_env, + WASMModuleInstance *module, + WASMMemoryInstance *memory, + WASMGlobalInstance *globals, + uint8 *global_data, + uint8 *global_addr, + WASMFunctionInstance *cur_func, + struct WASMInterpFrame *frame, + register uint8 *frame_ip, + register uint32 *frame_sp, + WASMBranchBlock *frame_csp, + // uint32 *frame_tsp, + uint8 *frame_ip_end, + uint8 *else_addr, + uint8 *end_addr, + uint8 *maddr, + bool done_flag) +{ + int rc; + struct timespec ts1, ts2; + // dump linear memory + clock_gettime(CLOCK_MONOTONIC, &ts1); + rc = wasm_dump_memory(memory); + clock_gettime(CLOCK_MONOTONIC, &ts2); + fprintf(stderr, "memory, %lu\n", get_time(ts1, ts2)); + if (rc < 0) { + LOG_ERROR("Failed to dump linear memory\n"); + return rc; + } + + // dump globals + clock_gettime(CLOCK_MONOTONIC, &ts1); + rc = wasm_dump_global(module, globals, global_data); + clock_gettime(CLOCK_MONOTONIC, &ts2); + fprintf(stderr, "global, %lu\n", get_time(ts1, ts2)); + if (rc < 0) { + LOG_ERROR("Failed to dump globals\n"); + return rc; + } + + // dump program counter + clock_gettime(CLOCK_MONOTONIC, &ts1); + rc = wasm_dump_program_counter(module, cur_func, frame_ip); + clock_gettime(CLOCK_MONOTONIC, &ts2); + fprintf(stderr, "program counter, %lu\n", get_time(ts1, ts2)); + if (rc < 0) { + LOG_ERROR("Failed to dump program_counter\n"); + return rc; + } + + // dump stack + clock_gettime(CLOCK_MONOTONIC, &ts1); + rc = wasm_dump_stack(exec_env, frame); + clock_gettime(CLOCK_MONOTONIC, &ts2); + fprintf(stderr, "stack, %lu\n", get_time(ts1, ts2)); + if (rc < 0) { + LOG_ERROR("Failed to dump frame\n"); + return rc; + } + + LOG_VERBOSE("Success to dump img for wamr\n"); + return 0; +} diff --git a/core/iwasm/migration/wasm_dump.h b/core/iwasm/migration/wasm_dump.h new file mode 100644 index 00000000..152376db --- /dev/null +++ b/core/iwasm/migration/wasm_dump.h @@ -0,0 +1,27 @@ +#ifndef _WASM_DUMP_H +#define _WASM_DUMP_H + +#include "../common/wasm_exec_env.h" +#include "../interpreter/wasm_interp.h" + +int wasm_dump(WASMExecEnv *exec_env, + WASMModuleInstance *module, + WASMMemoryInstance *memory, + WASMGlobalInstance *globals, + uint8 *global_data, + uint8 *global_addr, + WASMFunctionInstance *cur_func, + struct WASMInterpFrame *frame, + register uint8 *frame_ip, + register uint32 *frame_sp, + WASMBranchBlock *frame_csp, + // uint32 *frame_tsp, + uint8 *frame_ip_end, + uint8 *else_addr, + uint8 *end_addr, + uint8 *maddr, + bool done_flag); + +int64_t get_time(struct timespec ts1, struct timespec ts2); + +#endif // _WASM_CHECKPOINT_H diff --git a/core/iwasm/migration/wasm_migration.h b/core/iwasm/migration/wasm_migration.h new file mode 100644 index 00000000..a3a7503e --- /dev/null +++ b/core/iwasm/migration/wasm_migration.h @@ -0,0 +1,78 @@ +#ifndef _WASM_MIGRATION_H +#define _WASM_MIGRATION_H + +// #include "../common/wasm_exec_env.h" +#include "../interpreter/wasm_interp.h" + +static inline uint8 * +get_global_addr_for_migration(uint8 *global_data, WASMGlobalInstance *global) +{ +#if WASM_ENABLE_MULTI_MODULE == 0 + return global_data + global->data_offset; +#else + return global->import_global_inst + ? global->import_module_inst->global_data + + global->import_global_inst->data_offset + : global_data + global->data_offset; +#endif +} + +static uint32 +get_addr_offset(void* target, void* base) +{ + if (target == NULL) return -1; + else return target - base; +} + +static void* +set_addr_offset(void* base, uint32 offset) +{ + if (offset == -1) return NULL; + else return base + offset; +} + +static FILE* open_image(const char* file, const char* flag) { + FILE *fp = fopen(file, flag); + if (fp == NULL) { + fprintf(stderr, "failed to open %s\n", file); + return NULL; + } + return fp; +} + +// int wasm_dump(WASMExecEnv *exec_env, +// WASMModuleInstance *module, +// WASMMemoryInstance *memory, +// WASMGlobalInstance *globals, +// uint8 *global_data, +// uint8 *global_addr, +// WASMFunctionInstance *cur_func, +// struct WASMInterpFrame *frame, +// register uint8 *frame_ip, +// register uint32 *frame_sp, +// WASMBranchBlock *frame_csp, +// uint8 *frame_ip_end, +// uint8 *else_addr, +// uint8 *end_addr, +// uint8 *maddr, +// bool done_flag); + +// int wasm_restore(WASMModuleInstance *module, +// WASMExecEnv *exec_env, +// WASMFunctionInstance *cur_func, +// WASMInterpFrame *prev_frame, +// WASMMemoryInstance *memory, +// WASMGlobalInstance *globals, +// uint8 *global_data, +// uint8 *global_addr, +// WASMInterpFrame *frame, +// register uint8 *frame_ip, +// register uint32 *frame_lp, +// register uint32 *frame_sp, +// WASMBranchBlock *frame_csp, +// uint8 *frame_ip_end, +// uint8 *else_addr, +// uint8 *end_addr, +// uint8 *maddr, +// bool *done_flag); +#endif // _WASM_MIGRATION_H diff --git a/core/iwasm/migration/wasm_restore.c b/core/iwasm/migration/wasm_restore.c new file mode 100644 index 00000000..228e0756 --- /dev/null +++ b/core/iwasm/migration/wasm_restore.c @@ -0,0 +1,414 @@ +#include +#include + +#include "../common/wasm_exec_env.h" +#include "../common/wasm_memory.h" +#include "../interpreter/wasm_runtime.h" +#include "wasm_migration.h" +#include "wasm_restore.h" + +static bool restore_flag; +void set_restore_flag(bool f) +{ + restore_flag = f; +} +bool get_restore_flag() +{ + return restore_flag; +} + + +static inline WASMInterpFrame * +wasm_alloc_frame(WASMExecEnv *exec_env, uint32 size, WASMInterpFrame *prev_frame) +{ + WASMInterpFrame *frame = wasm_exec_env_alloc_wasm_frame(exec_env, size); + + 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, + "wasm operand stack overflow"); + } + + return frame; +} + +static void +debug_frame(WASMInterpFrame* frame) +{ + // fprintf(stderr, "Return Address: (%d, %d)\n", fidx, offset); + // fprintf(stderr, "TypeStack Content: ["); + // uint32* tsp_bottom = frame->tsp_bottom; + // for (uint32 i = 0; i < type_stack_size; ++i) { + // uint8 type = *(tsp_bottom+i); + // fprintf(stderr, "%d, ", type); + // } + // fprintf(stderr, "]\n"); + // fprintf(stderr, "Value Stack Size: %d\n", value_stack_size); + // fprintf(stderr, "Type Stack Size(Local含む): %d\n", full_type_stack_size); + // fprintf(stderr, "Type Stack Size(Local含まず): %d\n", type_stack_size); + // fprintf(stderr, "Label Stack Size: %d\n", ctrl_stack_size); + +} + +static void +debug_local(WASMInterpFrame *frame) +{ + WASMFunctionInstance *func = frame->function; + uint32 *lp = frame->lp; + uint32 param_count = func->param_count; + uint32 local_count = func->local_count; + + fprintf(stderr, "locals: ["); + for (uint32 i = 0; i < param_count; i++) { + switch (func->param_types[i]) { + case VALUE_TYPE_I32: + case VALUE_TYPE_F32: + fprintf(stderr, "%u, ", *(uint32 *)lp); + lp++; + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + fprintf(stderr, "%lu, ", *(uint64 *)lp); + lp += 2; + break; + default: + printf("TYPE NULL\n"); + break; + } + } + + /* local */ + for (uint32 i = 0; i < local_count; i++) { + switch (func->local_types[i]) { + case VALUE_TYPE_I32: + case VALUE_TYPE_F32: + fprintf(stderr, "%u, ", *(uint32 *)lp); + lp++; + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + fprintf(stderr, "%lu, ", *(uint64 *)lp); + lp += 2; + break; + default: + printf("TYPE NULL\n"); + break; + } + } + fprintf(stderr, "]\n"); +} + + +static void +debug_label_stack(WASMInterpFrame *frame) +{ + WASMBranchBlock *csp = frame->csp_bottom; + uint32 csp_num = frame->csp - csp; + + fprintf(stderr, "label stack: [\n"); + for (int i = 0; i < csp_num; i++, csp++) { + // uint8 *begin_addr; + fprintf(stderr, "\t{%d", + // csp->begin_addr == NULL ? -1 : csp->begin_addr - wasm_get_func_code(frame->function); + get_addr_offset(csp->begin_addr, wasm_get_func_code(frame->function)) + ); + + // uint8 *target_addr; + fprintf(stderr, ", %d", + get_addr_offset(csp->target_addr, wasm_get_func_code(frame->function)) + ); + + // uint32 *frame_sp; + fprintf(stderr, ", %d", + get_addr_offset(csp->frame_sp, frame->sp_bottom) + ); + + // uint32 *frame_tsp + // // fprintf(stderr, ", %d", + // // get_addr_offset(csp->frame_tsp, frame->tsp_bottom) + // ); + + // uint32 cell_num; + fprintf(stderr, ", %d", csp->cell_num); + + // uint32 count; + // fprintf(stderr, ", %d}\n", csp->count); + } + fprintf(stderr, "]\n"); +} + +static void +_restore_stack(WASMExecEnv *exec_env, WASMInterpFrame *frame, FILE *fp) +{ + WASMModuleInstance *module_inst = exec_env->module_inst; + WASMFunctionInstance *func = frame->function; + + // 初期化 + frame->sp_bottom = frame->lp + func->param_cell_num + func->local_cell_num; + frame->sp_boundary = frame->sp_bottom + func->u.func->max_stack_cell_num; + frame->csp_bottom = frame->sp_boundary; + frame->csp_boundary = frame->csp_bottom + func->u.func->max_block_num; + // frame->tsp_bottom = frame->csp_boundary; + // frame->tsp_boundary = frame->tsp_bottom + func->u.func->max_stack_cell_num; + + // リターンアドレス + WASMInterpFrame* prev_frame = frame->prev_frame; + uint32 fidx, offset; + fread(&fidx, sizeof(uint32), 1, fp); + fread(&offset, sizeof(uint32), 1, fp); + if (prev_frame->function != NULL) + prev_frame->ip = wasm_get_func_code(prev_frame->function) + offset; + + // 型スタックのサイズ + uint32 locals = func->param_count + func->local_count; + uint32 full_type_stack_size, type_stack_size; + fread(&full_type_stack_size, sizeof(uint32), 1, fp); + type_stack_size = full_type_stack_size - locals; // 統一フォーマットでは、ローカルも型/値スタックに入れているが、WAMRの型/値スタックのサイズはローカル抜き + // frame->tsp = frame->tsp_bottom + type_stack_size; + + // 型スタックの中身 + fseek(fp, sizeof(uint8)*locals, SEEK_CUR); // localのやつはWAMRでは必要ないので飛ばす + + uint8 type_stack[type_stack_size]; + // uint32* tsp_bottom = frame->tsp_bottom; + for (uint32 i = 0; i < type_stack_size; ++i) { + fread(&type_stack[i], sizeof(uint8), 1, fp); + } + + // 値スタックのサイズ + // uint32 *tsp = frame->tsp_bottom; + uint32 value_stack_size = 0; + for (uint32 i = 0; i < type_stack_size; ++i) { + value_stack_size += type_stack[i]; + } + frame->sp = frame->sp_bottom + value_stack_size; + + // 値スタックの中身 + uint32 local_cell_num = func->param_cell_num + func->local_cell_num; + fread(frame->lp, sizeof(uint32), local_cell_num, fp); + // debug_local(frame); + fread(frame->sp_bottom, sizeof(uint32), value_stack_size, fp); + + // ラベルスタックのサイズ + uint32 ctrl_stack_size; + fread(&ctrl_stack_size, sizeof(uint32), 1, fp); + frame->csp = frame->csp_bottom + ctrl_stack_size; + + + // ラベルスタックの中身 + WASMBranchBlock *csp = frame->csp_bottom; + for (int i = 0; i < ctrl_stack_size; ++i, ++csp) { + uint64 offset; + + // uint8 *begin_addr; + fread(&offset, sizeof(uint32), 1, fp); + csp->begin_addr = set_addr_offset(wasm_get_func_code(frame->function), offset); + + // uint8 *target_addr; + fread(&offset, sizeof(uint32), 1, fp); + csp->target_addr = set_addr_offset(wasm_get_func_code(frame->function), offset); + + // uint32 *frame_sp; + fread(&offset, sizeof(uint32), 1, fp); + csp->frame_sp = set_addr_offset(frame->sp_bottom, offset); + + // uint32 *frame_tsp + // fread(&offset, sizeof(uint32), 1, fp); + // csp->frame_tsp = set_addr_offset(frame->tsp_bottom, offset); + + // uint32 cell_num; + fread(&csp->cell_num, sizeof(uint32), 1, fp); + + // uint32 count; + // fread(&csp->count, sizeof(uint32), 1, fp); + } +} + +WASMInterpFrame* +wasm_restore_stack(WASMExecEnv **_exec_env) +{ + WASMExecEnv *exec_env = *_exec_env; + WASMModuleInstance *module_inst = + (WASMModuleInstance *)exec_env->module_inst; + WASMInterpFrame *frame, *prev_frame = wasm_exec_env_get_cur_frame(exec_env); + frame = prev_frame; + WASMFunctionInstance *function; + uint32 func_idx, frame_size, all_cell_num; + FILE *fp; + + uint32 frame_stack_size; + fp = open_image("frame.img", "rb"); + fread(&frame_stack_size, sizeof(uint32), 1, fp); + fclose(fp); + + char file[32]; + uint32 fidx = 0; + for (uint32 i = frame_stack_size; i > 0; --i) { + sprintf(file, "stack%d.img", i); + fp = open_image(file, "rb"); + + fread(&fidx, sizeof(uint32), 1, fp); + // 関数からスタックサイズを計算し,ALLOC + // 前のframe2のenter_func_idxが、このframe->functionに対応 + function = module_inst->e->functions + fidx; + + // TODO: uint64になってるけど、多分uint32 + all_cell_num = (uint32)function->param_cell_num + + (uint32)function->local_cell_num + + (uint32)function->u.func->max_stack_cell_num + + ((uint32)function->u.func->max_block_num) + * sizeof(WASMBranchBlock) / 4 + + (uint32)function->u.func->max_stack_cell_num; + frame_size = wasm_interp_interp_frame_size(all_cell_num); + frame = wasm_alloc_frame(exec_env, frame_size, + (WASMInterpFrame *)prev_frame); + + // フレームをrestore + frame->function = function; + _restore_stack(exec_env, frame, fp); + + prev_frame = frame; + fclose(fp); + } + + // debug_wasm_interp_frame(frame, module_inst->e->functions); + wasm_exec_env_set_cur_frame(exec_env, frame); + + _exec_env = &exec_env; + + return frame; +} + +void restore_dirty_memory(WASMMemoryInstance **memory, FILE* memory_fp) { + const int PAGE_SIZE = 4096; + while (!feof(memory_fp)) { + if (feof(memory_fp)) break; + uint32 offset; + uint32 len; + len = fread(&offset, sizeof(uint32), 1, memory_fp); + if (len == 0) break; + // printf("len: %d\n", len); + // printf("i: %d\n", offset); + + uint8* addr = (*memory)->memory_data + offset; + len = fread(addr, PAGE_SIZE, 1, memory_fp); + // printf("PAGESIZE: %d\n", len); + } +} + +int wasm_restore_memory(WASMModuleInstance *module, WASMMemoryInstance **memory, uint8** maddr) { + FILE* memory_fp = open_image("memory.img", "rb"); + FILE* mem_size_fp = open_image("mem_page_count.img", "rb"); + + // restore page_count + uint32 page_count; + fread(&page_count, sizeof(uint32), 1, mem_size_fp); + wasm_enlarge_memory(module, page_count- (*memory)->cur_page_count); + *maddr = page_count * (*memory)->num_bytes_per_page; + + restore_dirty_memory(memory, memory_fp); + // restore memory_data + // fread((*memory)->memory_data, sizeof(uint8), + // (*memory)->num_bytes_per_page * (*memory)->cur_page_count, memory_fp); + + fclose(memory_fp); + fclose(mem_size_fp); + return 0; +} + +int wasm_restore_global(const WASMModuleInstance *module, const WASMGlobalInstance *globals, uint8 **global_data, uint8 **global_addr) { + FILE* fp = open_image("global.img", "rb"); + + for (int i = 0; i < module->e->global_count; i++) { + switch (globals[i].type) { + case VALUE_TYPE_I32: + case VALUE_TYPE_F32: + *global_addr = get_global_addr_for_migration(*global_data, globals + i); + fread(*global_addr, sizeof(uint32), 1, fp); + break; + case VALUE_TYPE_I64: + case VALUE_TYPE_F64: + *global_addr = get_global_addr_for_migration(*global_data, globals + i); + fread(*global_addr, sizeof(uint64), 1, fp); + break; + default: + perror("wasm_restore_global:type error:A\n"); + break; + } + } + + fclose(fp); + return 0; +} + +void debug_addr(const char* name, const char* func_name, int value) { + if (value == NULL) { + fprintf(stderr, "debug_addr: %s value is NULL\n", name); + return; + } + printf("%s in %s: %p\n", name, func_name, (int)value); +} + +int wasm_restore_program_counter( + WASMModuleInstance *module, + uint8 **frame_ip) +{ + FILE* fp = open_image("program_counter.img", "rb"); + + uint32 fidx, offset; + fread(&fidx, sizeof(uint32), 1, fp); + fread(&offset, sizeof(uint32), 1, fp); + + *frame_ip = wasm_get_func_code(module->e->functions + fidx) + offset; + + return 0; +} + +int wasm_restore(WASMModuleInstance **module, + WASMExecEnv **exec_env, + WASMFunctionInstance **cur_func, + WASMInterpFrame **prev_frame, + WASMMemoryInstance **memory, + WASMGlobalInstance **globals, + uint8 **global_data, + uint8 **global_addr, + WASMInterpFrame **frame, + uint8 **frame_ip, + uint32 **frame_lp, + uint32 **frame_sp, + WASMBranchBlock **frame_csp, + uint8 **frame_ip_end, + uint8 **else_addr, + uint8 **end_addr, + uint8 **maddr, + bool *done_flag) +{ + struct timespec ts1, ts2; + // restore memory + clock_gettime(CLOCK_MONOTONIC, &ts1); + wasm_restore_memory(*module, memory, maddr); + clock_gettime(CLOCK_MONOTONIC, &ts2); + fprintf(stderr, "memory, %lu\n", get_time(ts1, ts2)); + // printf("Success to restore linear memory\n"); + + // restore globals + clock_gettime(CLOCK_MONOTONIC, &ts1); + wasm_restore_global(*module, *globals, global_data, global_addr); + clock_gettime(CLOCK_MONOTONIC, &ts2); + fprintf(stderr, "global, %lu\n", get_time(ts1, ts2)); + // printf("Success to restore globals\n"); + + // restore program counter + clock_gettime(CLOCK_MONOTONIC, &ts1); + wasm_restore_program_counter(*module, frame_ip); + clock_gettime(CLOCK_MONOTONIC, &ts2); + fprintf(stderr, "program counter, %lu\n", get_time(ts1, ts2)); + // printf("Success to program counter\n"); + + return 0; +} \ No newline at end of file diff --git a/core/iwasm/migration/wasm_restore.h b/core/iwasm/migration/wasm_restore.h new file mode 100644 index 00000000..eba5e420 --- /dev/null +++ b/core/iwasm/migration/wasm_restore.h @@ -0,0 +1,45 @@ +#ifndef _WASM_RESTORE_H +#define _WASM_RESTORE_H + +#include "../common/wasm_exec_env.h" +#include "../interpreter/wasm_interp.h" + +void set_restore_flag(bool f); +bool get_restore_flag(); + +WASMInterpFrame* +wasm_restore_stack(WASMExecEnv **exec_env); + +static inline void +debug_wasm_interp_frame(WASMInterpFrame *frame, WASMFunctionInstance* base_func_addr) { + int cnt = 0; + printf("=== dump frames ===\n"); + do { + cnt++; + if (frame->function == NULL) + printf("frame: %d, func idx: DUMMY\n", cnt); + else + printf("frame: %d func idx: %d\n", cnt, frame->function-base_func_addr); + } while(frame = frame->prev_frame); + printf("=== dump frames ===\n"); +}; + +int wasm_restore(WASMModuleInstance **module, + WASMExecEnv **exec_env, + WASMFunctionInstance **cur_func, + WASMInterpFrame **prev_frame, + WASMMemoryInstance **memory, + WASMGlobalInstance **globals, + uint8 **global_data, + uint8 **global_addr, + WASMInterpFrame **frame, + uint8 **frame_ip, + uint32 **frame_lp, + uint32 **frame_sp, + WASMBranchBlock **frame_csp, + uint8 **frame_ip_end, + uint8 **else_addr, + uint8 **end_addr, + uint8 **maddr, + bool *done_flag); +#endif // _WASM_RESTORE_H \ No newline at end of file diff --git a/product-mini/platforms/posix/main.c b/product-mini/platforms/posix/main.c index b2f929c6..3b27eeab 100644 --- a/product-mini/platforms/posix/main.c +++ b/product-mini/platforms/posix/main.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "bh_platform.h" #include "bh_read_file.h" @@ -106,6 +107,7 @@ print_help() #if WASM_ENABLE_STATIC_PGO != 0 printf(" --gen-prof-file= Generate LLVM PGO (Profile-Guided Optimization) profile file\n"); #endif + printf(" --restore Restore from frame.img and interp.img\n"); printf(" --version Show version information\n"); return 1; } @@ -560,12 +562,18 @@ timeout_thread(void *vp) int main(int argc, char *argv[]) { + // リストアの初期化時間の計測(開始) + struct timespec ts1; + clock_gettime(CLOCK_MONOTONIC, &ts1); + fprintf(stderr, "boot_start, %lu\n", (uint64_t)(ts1.tv_sec*1e9) + ts1.tv_nsec); + int32 ret = -1; char *wasm_file = NULL; const char *func_name = NULL; uint8 *wasm_file_buf = NULL; uint32 wasm_file_size; uint32 stack_size = 64 * 1024; + bool restore_flag = false; #if WASM_ENABLE_LIBC_WASI != 0 uint32 heap_size = 0; #else @@ -792,7 +800,10 @@ main(int argc, char *argv[]) gen_prof_file = argv[0] + 16; } #endif - else if (!strcmp(argv[0], "--version")) { + else if (!strncmp(argv[0], "--restore", 9)) { + restore_flag = true; + } + else if (!strncmp(argv[0], "--version", 9)) { uint32 major, minor, patch; wasm_runtime_get_version(&major, &minor, &patch); printf("iwasm %" PRIu32 ".%" PRIu32 ".%" PRIu32 "\n", major, minor, @@ -827,6 +838,7 @@ main(int argc, char *argv[]) memset(&init_args, 0, sizeof(RuntimeInitArgs)); init_args.running_mode = running_mode; + init_args.restore_flag = restore_flag; #if WASM_ENABLE_GLOBAL_HEAP_POOL != 0 init_args.mem_alloc_type = Alloc_With_Pool; init_args.mem_alloc_option.pool.heap_buf = global_heap_buf;