Enhance wasm loading with LoadArgs and support module names (#3265)

- Add new API wasm_runtime_load_ex() in wasm_export.h
  and wasm_module_new_ex in wasm_c_api.h
- Put aot_create_perf_map() into a separated file aot_perf_map.c
- In perf.map, function names include user specified module name
- Enhance the script to help flamegraph generations
This commit is contained in:
liang.he
2024-04-07 15:04:35 +08:00
committed by GitHub
parent cee9b826a5
commit 4ef724bbff
28 changed files with 3008 additions and 346 deletions

View File

@ -16,6 +16,10 @@
#include "debug/jit_debug.h"
#endif
#if WASM_ENABLE_LINUX_PERF != 0
#include "aot_perf_map.h"
#endif
#define YMM_PLT_PREFIX "__ymm@"
#define XMM_PLT_PREFIX "__xmm@"
#define REAL_PLT_PREFIX "__real@"
@ -3601,104 +3605,6 @@ fail:
return ret;
}
#if WASM_ENABLE_LINUX_PERF != 0
struct func_info {
uint32 idx;
void *ptr;
};
static uint32
get_func_size(const AOTModule *module, struct func_info *sorted_func_ptrs,
uint32 idx)
{
uint32 func_sz;
if (idx == module->func_count - 1)
func_sz = (uintptr_t)module->code + module->code_size
- (uintptr_t)(sorted_func_ptrs[idx].ptr);
else
func_sz = (uintptr_t)(sorted_func_ptrs[idx + 1].ptr)
- (uintptr_t)(sorted_func_ptrs[idx].ptr);
return func_sz;
}
static int
compare_func_ptrs(const void *f1, const void *f2)
{
return (intptr_t)((struct func_info *)f1)->ptr
- (intptr_t)((struct func_info *)f2)->ptr;
}
static struct func_info *
sort_func_ptrs(const AOTModule *module, char *error_buf, uint32 error_buf_size)
{
uint64 content_len;
struct func_info *sorted_func_ptrs;
unsigned i;
content_len = (uint64)sizeof(struct func_info) * module->func_count;
sorted_func_ptrs = loader_malloc(content_len, error_buf, error_buf_size);
if (!sorted_func_ptrs)
return NULL;
for (i = 0; i < module->func_count; i++) {
sorted_func_ptrs[i].idx = i;
sorted_func_ptrs[i].ptr = module->func_ptrs[i];
}
qsort(sorted_func_ptrs, module->func_count, sizeof(struct func_info),
compare_func_ptrs);
return sorted_func_ptrs;
}
static bool
create_perf_map(const AOTModule *module, char *error_buf, uint32 error_buf_size)
{
struct func_info *sorted_func_ptrs = NULL;
char perf_map_info[128] = { 0 };
FILE *perf_map = NULL;
uint32 i;
pid_t pid = getpid();
bool ret = false;
sorted_func_ptrs = sort_func_ptrs(module, error_buf, error_buf_size);
if (!sorted_func_ptrs)
goto quit;
snprintf(perf_map_info, 128, "/tmp/perf-%d.map", pid);
perf_map = fopen(perf_map_info, "w");
if (!perf_map) {
LOG_WARNING("warning: can't create /tmp/perf-%d.map, because %s", pid,
strerror(errno));
goto quit;
}
for (i = 0; i < module->func_count; i++) {
memset(perf_map_info, 0, 128);
snprintf(perf_map_info, 128, "%lx %x aot_func#%u\n",
(uintptr_t)sorted_func_ptrs[i].ptr,
get_func_size(module, sorted_func_ptrs, i),
sorted_func_ptrs[i].idx);
fwrite(perf_map_info, 1, strlen(perf_map_info), perf_map);
}
LOG_VERBOSE("generate /tmp/perf-%d.map", pid);
ret = true;
quit:
if (sorted_func_ptrs)
free(sorted_func_ptrs);
if (perf_map)
fclose(perf_map);
return ret;
}
#endif /* WASM_ENABLE_LINUX_PERF != 0*/
static bool
load_from_sections(AOTModule *module, AOTSection *sections,
bool is_load_from_file_buf, char *error_buf,
@ -3889,7 +3795,7 @@ load_from_sections(AOTModule *module, AOTSection *sections,
}
static AOTModule *
create_module(char *error_buf, uint32 error_buf_size)
create_module(char *name, char *error_buf, uint32 error_buf_size)
{
AOTModule *module =
loader_malloc(sizeof(AOTModule), error_buf, error_buf_size);
@ -3901,7 +3807,7 @@ create_module(char *error_buf, uint32 error_buf_size)
module->module_type = Wasm_Module_AoT;
module->name = "";
module->name = name;
#if WASM_ENABLE_MULTI_MODULE != 0
module->import_module_list = &module->import_module_list_head;
@ -3937,7 +3843,7 @@ AOTModule *
aot_load_from_sections(AOTSection *section_list, char *error_buf,
uint32 error_buf_size)
{
AOTModule *module = create_module(error_buf, error_buf_size);
AOTModule *module = create_module("", error_buf, error_buf_size);
if (!module)
return NULL;
@ -4183,7 +4089,7 @@ load(const uint8 *buf, uint32 size, AOTModule *module, char *error_buf,
#if WASM_ENABLE_LINUX_PERF != 0
if (wasm_runtime_get_linux_perf())
if (!create_perf_map(module, error_buf, error_buf_size))
if (!aot_create_perf_map(module, error_buf, error_buf_size))
goto fail;
#endif
@ -4193,10 +4099,10 @@ fail:
}
AOTModule *
aot_load_from_aot_file(const uint8 *buf, uint32 size, char *error_buf,
uint32 error_buf_size)
aot_load_from_aot_file(const uint8 *buf, uint32 size, const LoadArgs *args,
char *error_buf, uint32 error_buf_size)
{
AOTModule *module = create_module(error_buf, error_buf_size);
AOTModule *module = create_module(args->name, error_buf, error_buf_size);
if (!module)
return NULL;

View File

@ -0,0 +1,120 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#include "aot_perf_map.h"
#include "bh_log.h"
#include "bh_platform.h"
#if WASM_ENABLE_LINUX_PERF != 0
struct func_info {
uint32 idx;
void *ptr;
};
static uint32
get_func_size(const AOTModule *module, struct func_info *sorted_func_ptrs,
uint32 idx)
{
uint32 func_sz;
if (idx == module->func_count - 1)
func_sz = (uintptr_t)module->code + module->code_size
- (uintptr_t)(sorted_func_ptrs[idx].ptr);
else
func_sz = (uintptr_t)(sorted_func_ptrs[idx + 1].ptr)
- (uintptr_t)(sorted_func_ptrs[idx].ptr);
return func_sz;
}
static int
compare_func_ptrs(const void *f1, const void *f2)
{
return (intptr_t)((struct func_info *)f1)->ptr
- (intptr_t)((struct func_info *)f2)->ptr;
}
static struct func_info *
sort_func_ptrs(const AOTModule *module, char *error_buf, uint32 error_buf_size)
{
uint64 content_len;
struct func_info *sorted_func_ptrs;
unsigned i;
content_len = (uint64)sizeof(struct func_info) * module->func_count;
sorted_func_ptrs = wasm_runtime_malloc(content_len);
if (!sorted_func_ptrs) {
snprintf(error_buf, error_buf_size,
"allocate memory failed when creating perf map");
return NULL;
}
for (i = 0; i < module->func_count; i++) {
sorted_func_ptrs[i].idx = i;
sorted_func_ptrs[i].ptr = module->func_ptrs[i];
}
qsort(sorted_func_ptrs, module->func_count, sizeof(struct func_info),
compare_func_ptrs);
return sorted_func_ptrs;
}
bool
aot_create_perf_map(const AOTModule *module, char *error_buf,
uint32 error_buf_size)
{
struct func_info *sorted_func_ptrs = NULL;
char perf_map_path[64] = { 0 };
char perf_map_info[128] = { 0 };
FILE *perf_map = NULL;
uint32 i;
pid_t pid = getpid();
bool ret = false;
sorted_func_ptrs = sort_func_ptrs(module, error_buf, error_buf_size);
if (!sorted_func_ptrs)
goto quit;
snprintf(perf_map_path, sizeof(perf_map_path) - 1, "/tmp/perf-%d.map", pid);
perf_map = fopen(perf_map_path, "a");
if (!perf_map) {
LOG_WARNING("warning: can't create /tmp/perf-%d.map, because %s", pid,
strerror(errno));
goto quit;
}
const char *module_name = aot_get_module_name((AOTModule *)module);
for (i = 0; i < module->func_count; i++) {
memset(perf_map_info, 0, 128);
if (strlen(module_name) > 0)
snprintf(perf_map_info, 128, "%lx %x [%s]#aot_func#%u\n",
(uintptr_t)sorted_func_ptrs[i].ptr,
get_func_size(module, sorted_func_ptrs, i), module_name,
sorted_func_ptrs[i].idx);
else
snprintf(perf_map_info, 128, "%lx %x aot_func#%u\n",
(uintptr_t)sorted_func_ptrs[i].ptr,
get_func_size(module, sorted_func_ptrs, i),
sorted_func_ptrs[i].idx);
/* fwrite() is thread safe */
fwrite(perf_map_info, 1, strlen(perf_map_info), perf_map);
}
LOG_VERBOSE("write map information from %s into /tmp/perf-%d.map",
module_name, pid);
ret = true;
quit:
if (sorted_func_ptrs)
wasm_runtime_free(sorted_func_ptrs);
if (perf_map)
fclose(perf_map);
return ret;
}
#endif /* WASM_ENABLE_LINUX_PERF != 0 */

View File

@ -0,0 +1,15 @@
/*
* Copyright (C) 2019 Intel Corporation. All rights reserved.
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
*/
#ifndef _AOT_PERF_MAP_H_
#define _AOT_PERF_MAP_H_
#include "aot_runtime.h"
bool
aot_create_perf_map(const AOTModule *module, char *error_buf,
uint32 error_buf_size);
#endif /* _AOT_PERF_MAP_H_ */

View File

@ -444,8 +444,8 @@ typedef struct LLVMProfileData_64 {
* @return return AOT module loaded, NULL if failed
*/
AOTModule *
aot_load_from_aot_file(const uint8 *buf, uint32 size, char *error_buf,
uint32 error_buf_size);
aot_load_from_aot_file(const uint8 *buf, uint32 size, const LoadArgs *args,
char *error_buf, uint32 error_buf_size);
/**
* Load a AOT module from a specified AOT section list.

View File

@ -2234,7 +2234,8 @@ quit:
#endif /* WASM_ENABLE_WASM_CACHE != 0 */
wasm_module_t *
wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary)
wasm_module_new_ex(wasm_store_t *store, const wasm_byte_vec_t *binary,
const LoadArgs *args)
{
char error_buf[128] = { 0 };
wasm_module_ex_t *module_ex = NULL;
@ -2290,8 +2291,8 @@ wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary)
if (!module_ex->binary->data)
goto free_binary;
module_ex->module_comm_rt = wasm_runtime_load(
(uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size,
module_ex->module_comm_rt = wasm_runtime_load_ex(
(uint8 *)module_ex->binary->data, (uint32)module_ex->binary->size, args,
error_buf, (uint32)sizeof(error_buf));
if (!(module_ex->module_comm_rt)) {
LOG_ERROR("%s", error_buf);
@ -2337,6 +2338,14 @@ quit:
return NULL;
}
wasm_module_t *
wasm_module_new(wasm_store_t *store, const wasm_byte_vec_t *binary)
{
LoadArgs args = { 0 };
args.name = "";
return wasm_module_new_ex(store, binary, &args);
}
bool
wasm_module_validate(wasm_store_t *store, const wasm_byte_vec_t *binary)
{

View File

@ -65,7 +65,7 @@
#if WASM_ENABLE_MULTI_MODULE != 0
/**
* A safety insurance to prevent
* circular depencies which leads stack overflow
* circular dependencies which leads stack overflow
* try to break early
*/
typedef struct LoadingModule {
@ -1333,11 +1333,15 @@ register_module_with_null_name(WASMModuleCommon *module_common, char *error_buf,
}
WASMModuleCommon *
wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf,
uint32 error_buf_size)
wasm_runtime_load_ex(uint8 *buf, uint32 size, const LoadArgs *args,
char *error_buf, uint32 error_buf_size)
{
WASMModuleCommon *module_common = NULL;
if (!args) {
return NULL;
}
if (get_package_type(buf, size) == Wasm_Module_Bytecode) {
#if WASM_ENABLE_INTERP != 0
module_common =
@ -1345,13 +1349,13 @@ wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf,
#if WASM_ENABLE_MULTI_MODULE != 0
true,
#endif
error_buf, error_buf_size);
args, error_buf, error_buf_size);
#endif
}
else if (get_package_type(buf, size) == Wasm_Module_AoT) {
#if WASM_ENABLE_AOT != 0
module_common = (WASMModuleCommon *)aot_load_from_aot_file(
buf, size, error_buf, error_buf_size);
buf, size, args, error_buf, error_buf_size);
#endif
}
else {
@ -1367,10 +1371,21 @@ wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf,
LOG_DEBUG("WASM module load failed");
return NULL;
}
/*TODO: use file name as name and register with name? */
return register_module_with_null_name(module_common, error_buf,
error_buf_size);
}
WASMModuleCommon *
wasm_runtime_load(uint8 *buf, uint32 size, char *error_buf,
uint32 error_buf_size)
{
LoadArgs args = { 0 };
args.name = "";
return wasm_runtime_load_ex(buf, size, &args, error_buf, error_buf_size);
}
WASMModuleCommon *
wasm_runtime_load_from_sections(WASMSection *section_list, bool is_aot,
char *error_buf, uint32 error_buf_size)
@ -6501,6 +6516,7 @@ wasm_runtime_load_depended_module(const WASMModuleCommon *parent_module,
bool ret = false;
uint8 *buffer = NULL;
uint32 buffer_size = 0;
LoadArgs args = { 0 };
/* check the registered module list of the parent */
sub_module = wasm_runtime_search_sub_module(parent_module, sub_module_name);
@ -6547,16 +6563,18 @@ wasm_runtime_load_depended_module(const WASMModuleCommon *parent_module,
LOG_DEBUG("moudle %s type error", sub_module_name);
goto destroy_file_buffer;
}
args.name = (char *)sub_module_name;
if (get_package_type(buffer, buffer_size) == Wasm_Module_Bytecode) {
#if WASM_ENABLE_INTERP != 0
sub_module = (WASMModuleCommon *)wasm_load(buffer, buffer_size, false,
error_buf, error_buf_size);
sub_module = (WASMModuleCommon *)wasm_load(
buffer, buffer_size, false, &args, error_buf, error_buf_size);
#endif
}
else if (get_package_type(buffer, buffer_size) == Wasm_Module_AoT) {
#if WASM_ENABLE_AOT != 0
sub_module = (WASMModuleCommon *)aot_load_from_aot_file(
buffer, buffer_size, error_buf, error_buf_size);
buffer, buffer_size, &args, error_buf, error_buf_size);
#endif
}
if (!sub_module) {

View File

@ -85,7 +85,7 @@ aot_add_llvm_func1(const AOTCompContext *comp_ctx, LLVMModuleRef module,
uint32 func_index, uint32 param_count, LLVMTypeRef func_type,
const char *prefix)
{
char func_name[48];
char func_name[48] = { 0 };
LLVMValueRef func;
LLVMValueRef local_value;
uint32 i, j;

View File

@ -517,10 +517,21 @@ struct WASMModuleCommon;
typedef struct WASMModuleCommon *wasm_module_t;
#endif
#ifndef LOAD_ARGS_OPTION_DEFINED
#define LOAD_ARGS_OPTION_DEFINED
typedef struct LoadArgs {
char *name;
/* TODO: more fields? */
} LoadArgs;
#endif /* LOAD_ARGS_OPTION_DEFINED */
WASM_API_EXTERN own wasm_module_t* wasm_module_new(
wasm_store_t*, const wasm_byte_vec_t* binary);
// please refer to wasm_runtime_load_ex(...) in core/iwasm/include/wasm_export.h
WASM_API_EXTERN own wasm_module_t* wasm_module_new_ex(
wasm_store_t*, const wasm_byte_vec_t* binary, const LoadArgs *args);
WASM_API_EXTERN void wasm_module_delete(own wasm_module_t*);
WASM_API_EXTERN bool wasm_module_validate(wasm_store_t*, const wasm_byte_vec_t* binary);

View File

@ -183,6 +183,14 @@ typedef struct RuntimeInitArgs {
bool enable_linux_perf;
} RuntimeInitArgs;
#ifndef LOAD_ARGS_OPTION_DEFINED
#define LOAD_ARGS_OPTION_DEFINED
typedef struct LoadArgs {
char *name;
/* TODO: more fields? */
} LoadArgs;
#endif /* LOAD_ARGS_OPTION_DEFINED */
#ifndef INSTANTIATION_ARGS_OPTION_DEFINED
#define INSTANTIATION_ARGS_OPTION_DEFINED
/* WASM module instantiation arguments */
@ -419,6 +427,13 @@ WASM_RUNTIME_API_EXTERN wasm_module_t
wasm_runtime_load(uint8_t *buf, uint32_t size,
char *error_buf, uint32_t error_buf_size);
/**
* Load a WASM module with specified load argument.
*/
WASM_RUNTIME_API_EXTERN wasm_module_t
wasm_runtime_load_ex(uint8_t *buf, uint32_t size, const LoadArgs *args,
char *error_buf, uint32_t error_buf_size);
/**
* Load a WASM module from a specified WASM or AOT section list.
*

View File

@ -6043,7 +6043,7 @@ load_from_sections(WASMModule *module, WASMSection *sections,
}
static WASMModule *
create_module(char *error_buf, uint32 error_buf_size)
create_module(char *name, char *error_buf, uint32 error_buf_size)
{
WASMModule *module =
loader_malloc(sizeof(WASMModule), error_buf, error_buf_size);
@ -6058,7 +6058,7 @@ create_module(char *error_buf, uint32 error_buf_size)
/* Set start_function to -1, means no start function */
module->start_function = (uint32)-1;
module->name = "";
module->name = name;
#if WASM_ENABLE_FAST_INTERP == 0
module->br_table_cache_list = &module->br_table_cache_list_head;
@ -6138,7 +6138,7 @@ WASMModule *
wasm_loader_load_from_sections(WASMSection *section_list, char *error_buf,
uint32 error_buf_size)
{
WASMModule *module = create_module(error_buf, error_buf_size);
WASMModule *module = create_module("", error_buf, error_buf_size);
if (!module)
return NULL;
@ -6479,9 +6479,9 @@ wasm_loader_load(uint8 *buf, uint32 size,
#if WASM_ENABLE_MULTI_MODULE != 0
bool main_module,
#endif
char *error_buf, uint32 error_buf_size)
const LoadArgs *args, char *error_buf, uint32 error_buf_size)
{
WASMModule *module = create_module(error_buf, error_buf_size);
WASMModule *module = create_module(args->name, error_buf, error_buf_size);
if (!module) {
return NULL;
}

View File

@ -28,7 +28,7 @@ wasm_loader_load(uint8 *buf, uint32 size,
#if WASM_ENABLE_MULTI_MODULE != 0
bool main_module,
#endif
char *error_buf, uint32 error_buf_size);
const LoadArgs *args, char *error_buf, uint32 error_buf_size);
/**
* Load a WASM module from a specified WASM section list.

View File

@ -2994,7 +2994,7 @@ load_from_sections(WASMModule *module, WASMSection *sections,
}
static WASMModule *
create_module(char *error_buf, uint32 error_buf_size)
create_module(char *name, char *error_buf, uint32 error_buf_size)
{
WASMModule *module =
loader_malloc(sizeof(WASMModule), error_buf, error_buf_size);
@ -3009,7 +3009,7 @@ create_module(char *error_buf, uint32 error_buf_size)
/* Set start_function to -1, means no start function */
module->start_function = (uint32)-1;
module->name = "";
module->name = name;
#if WASM_ENABLE_FAST_INTERP == 0
module->br_table_cache_list = &module->br_table_cache_list_head;
@ -3035,7 +3035,7 @@ WASMModule *
wasm_loader_load_from_sections(WASMSection *section_list, char *error_buf,
uint32 error_buf_size)
{
WASMModule *module = create_module(error_buf, error_buf_size);
WASMModule *module = create_module("", error_buf, error_buf_size);
if (!module)
return NULL;
@ -3206,10 +3206,10 @@ load(const uint8 *buf, uint32 size, WASMModule *module, char *error_buf,
}
WASMModule *
wasm_loader_load(uint8 *buf, uint32 size, char *error_buf,
wasm_loader_load(uint8 *buf, uint32 size, const LoadArgs *args, char *error_buf,
uint32 error_buf_size)
{
WASMModule *module = create_module(error_buf, error_buf_size);
WASMModule *module = create_module(args->name, error_buf, error_buf_size);
if (!module) {
return NULL;
}

View File

@ -60,13 +60,13 @@ wasm_load(uint8 *buf, uint32 size,
#if WASM_ENABLE_MULTI_MODULE != 0
bool main_module,
#endif
char *error_buf, uint32 error_buf_size)
const LoadArgs *name, char *error_buf, uint32 error_buf_size)
{
return wasm_loader_load(buf, size,
#if WASM_ENABLE_MULTI_MODULE != 0
main_module,
#endif
error_buf, error_buf_size);
name, error_buf, error_buf_size);
}
WASMModule *

View File

@ -508,7 +508,7 @@ wasm_load(uint8 *buf, uint32 size,
#if WASM_ENABLE_MULTI_MODULE != 0
bool main_module,
#endif
char *error_buf, uint32 error_buf_size);
const LoadArgs *args, char *error_buf, uint32 error_buf_size);
WASMModule *
wasm_load_from_sections(WASMSection *section_list, char *error_buf,