/* * 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 */