18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * db-export.c: Support for exporting data suitable for import to a database 48c2ecf20Sopenharmony_ci * Copyright (c) 2014, Intel Corporation. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#include <errno.h> 88c2ecf20Sopenharmony_ci#include <stdlib.h> 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include "dso.h" 118c2ecf20Sopenharmony_ci#include "evsel.h" 128c2ecf20Sopenharmony_ci#include "machine.h" 138c2ecf20Sopenharmony_ci#include "thread.h" 148c2ecf20Sopenharmony_ci#include "comm.h" 158c2ecf20Sopenharmony_ci#include "symbol.h" 168c2ecf20Sopenharmony_ci#include "map.h" 178c2ecf20Sopenharmony_ci#include "event.h" 188c2ecf20Sopenharmony_ci#include "thread-stack.h" 198c2ecf20Sopenharmony_ci#include "callchain.h" 208c2ecf20Sopenharmony_ci#include "call-path.h" 218c2ecf20Sopenharmony_ci#include "db-export.h" 228c2ecf20Sopenharmony_ci#include <linux/zalloc.h> 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ciint db_export__init(struct db_export *dbe) 258c2ecf20Sopenharmony_ci{ 268c2ecf20Sopenharmony_ci memset(dbe, 0, sizeof(struct db_export)); 278c2ecf20Sopenharmony_ci return 0; 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_civoid db_export__exit(struct db_export *dbe) 318c2ecf20Sopenharmony_ci{ 328c2ecf20Sopenharmony_ci call_return_processor__free(dbe->crp); 338c2ecf20Sopenharmony_ci dbe->crp = NULL; 348c2ecf20Sopenharmony_ci} 358c2ecf20Sopenharmony_ci 368c2ecf20Sopenharmony_ciint db_export__evsel(struct db_export *dbe, struct evsel *evsel) 378c2ecf20Sopenharmony_ci{ 388c2ecf20Sopenharmony_ci if (evsel->db_id) 398c2ecf20Sopenharmony_ci return 0; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci evsel->db_id = ++dbe->evsel_last_db_id; 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci if (dbe->export_evsel) 448c2ecf20Sopenharmony_ci return dbe->export_evsel(dbe, evsel); 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci return 0; 478c2ecf20Sopenharmony_ci} 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ciint db_export__machine(struct db_export *dbe, struct machine *machine) 508c2ecf20Sopenharmony_ci{ 518c2ecf20Sopenharmony_ci if (machine->db_id) 528c2ecf20Sopenharmony_ci return 0; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci machine->db_id = ++dbe->machine_last_db_id; 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci if (dbe->export_machine) 578c2ecf20Sopenharmony_ci return dbe->export_machine(dbe, machine); 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci return 0; 608c2ecf20Sopenharmony_ci} 618c2ecf20Sopenharmony_ci 628c2ecf20Sopenharmony_ciint db_export__thread(struct db_export *dbe, struct thread *thread, 638c2ecf20Sopenharmony_ci struct machine *machine, struct thread *main_thread) 648c2ecf20Sopenharmony_ci{ 658c2ecf20Sopenharmony_ci u64 main_thread_db_id = 0; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci if (thread->db_id) 688c2ecf20Sopenharmony_ci return 0; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci thread->db_id = ++dbe->thread_last_db_id; 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci if (main_thread) 738c2ecf20Sopenharmony_ci main_thread_db_id = main_thread->db_id; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci if (dbe->export_thread) 768c2ecf20Sopenharmony_ci return dbe->export_thread(dbe, thread, main_thread_db_id, 778c2ecf20Sopenharmony_ci machine); 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci return 0; 808c2ecf20Sopenharmony_ci} 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_cistatic int __db_export__comm(struct db_export *dbe, struct comm *comm, 838c2ecf20Sopenharmony_ci struct thread *thread) 848c2ecf20Sopenharmony_ci{ 858c2ecf20Sopenharmony_ci comm->db_id = ++dbe->comm_last_db_id; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci if (dbe->export_comm) 888c2ecf20Sopenharmony_ci return dbe->export_comm(dbe, comm, thread); 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci return 0; 918c2ecf20Sopenharmony_ci} 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ciint db_export__comm(struct db_export *dbe, struct comm *comm, 948c2ecf20Sopenharmony_ci struct thread *thread) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci if (comm->db_id) 978c2ecf20Sopenharmony_ci return 0; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci return __db_export__comm(dbe, comm, thread); 1008c2ecf20Sopenharmony_ci} 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci/* 1038c2ecf20Sopenharmony_ci * Export the "exec" comm. The "exec" comm is the program / application command 1048c2ecf20Sopenharmony_ci * name at the time it first executes. It is used to group threads for the same 1058c2ecf20Sopenharmony_ci * program. Note that the main thread pid (or thread group id tgid) cannot be 1068c2ecf20Sopenharmony_ci * used because it does not change when a new program is exec'ed. 1078c2ecf20Sopenharmony_ci */ 1088c2ecf20Sopenharmony_ciint db_export__exec_comm(struct db_export *dbe, struct comm *comm, 1098c2ecf20Sopenharmony_ci struct thread *main_thread) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci int err; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (comm->db_id) 1148c2ecf20Sopenharmony_ci return 0; 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_ci err = __db_export__comm(dbe, comm, main_thread); 1178c2ecf20Sopenharmony_ci if (err) 1188c2ecf20Sopenharmony_ci return err; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci /* 1218c2ecf20Sopenharmony_ci * Record the main thread for this comm. Note that the main thread can 1228c2ecf20Sopenharmony_ci * have many "exec" comms because there will be a new one every time it 1238c2ecf20Sopenharmony_ci * exec's. An "exec" comm however will only ever have 1 main thread. 1248c2ecf20Sopenharmony_ci * That is different to any other threads for that same program because 1258c2ecf20Sopenharmony_ci * exec() will effectively kill them, so the relationship between the 1268c2ecf20Sopenharmony_ci * "exec" comm and non-main threads is 1-to-1. That is why 1278c2ecf20Sopenharmony_ci * db_export__comm_thread() is called here for the main thread, but it 1288c2ecf20Sopenharmony_ci * is called for non-main threads when they are exported. 1298c2ecf20Sopenharmony_ci */ 1308c2ecf20Sopenharmony_ci return db_export__comm_thread(dbe, comm, main_thread); 1318c2ecf20Sopenharmony_ci} 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ciint db_export__comm_thread(struct db_export *dbe, struct comm *comm, 1348c2ecf20Sopenharmony_ci struct thread *thread) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci u64 db_id; 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci db_id = ++dbe->comm_thread_last_db_id; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci if (dbe->export_comm_thread) 1418c2ecf20Sopenharmony_ci return dbe->export_comm_thread(dbe, db_id, comm, thread); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return 0; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ciint db_export__dso(struct db_export *dbe, struct dso *dso, 1478c2ecf20Sopenharmony_ci struct machine *machine) 1488c2ecf20Sopenharmony_ci{ 1498c2ecf20Sopenharmony_ci if (dso->db_id) 1508c2ecf20Sopenharmony_ci return 0; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci dso->db_id = ++dbe->dso_last_db_id; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_ci if (dbe->export_dso) 1558c2ecf20Sopenharmony_ci return dbe->export_dso(dbe, dso, machine); 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ci return 0; 1588c2ecf20Sopenharmony_ci} 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ciint db_export__symbol(struct db_export *dbe, struct symbol *sym, 1618c2ecf20Sopenharmony_ci struct dso *dso) 1628c2ecf20Sopenharmony_ci{ 1638c2ecf20Sopenharmony_ci u64 *sym_db_id = symbol__priv(sym); 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci if (*sym_db_id) 1668c2ecf20Sopenharmony_ci return 0; 1678c2ecf20Sopenharmony_ci 1688c2ecf20Sopenharmony_ci *sym_db_id = ++dbe->symbol_last_db_id; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (dbe->export_symbol) 1718c2ecf20Sopenharmony_ci return dbe->export_symbol(dbe, sym, dso); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic int db_ids_from_al(struct db_export *dbe, struct addr_location *al, 1778c2ecf20Sopenharmony_ci u64 *dso_db_id, u64 *sym_db_id, u64 *offset) 1788c2ecf20Sopenharmony_ci{ 1798c2ecf20Sopenharmony_ci int err; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (al->map) { 1828c2ecf20Sopenharmony_ci struct dso *dso = al->map->dso; 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci err = db_export__dso(dbe, dso, al->maps->machine); 1858c2ecf20Sopenharmony_ci if (err) 1868c2ecf20Sopenharmony_ci return err; 1878c2ecf20Sopenharmony_ci *dso_db_id = dso->db_id; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (!al->sym) { 1908c2ecf20Sopenharmony_ci al->sym = symbol__new(al->addr, 0, 0, 0, "unknown"); 1918c2ecf20Sopenharmony_ci if (al->sym) 1928c2ecf20Sopenharmony_ci dso__insert_symbol(dso, al->sym); 1938c2ecf20Sopenharmony_ci } 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci if (al->sym) { 1968c2ecf20Sopenharmony_ci u64 *db_id = symbol__priv(al->sym); 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci err = db_export__symbol(dbe, al->sym, dso); 1998c2ecf20Sopenharmony_ci if (err) 2008c2ecf20Sopenharmony_ci return err; 2018c2ecf20Sopenharmony_ci *sym_db_id = *db_id; 2028c2ecf20Sopenharmony_ci *offset = al->addr - al->sym->start; 2038c2ecf20Sopenharmony_ci } 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci return 0; 2078c2ecf20Sopenharmony_ci} 2088c2ecf20Sopenharmony_ci 2098c2ecf20Sopenharmony_cistatic struct call_path *call_path_from_sample(struct db_export *dbe, 2108c2ecf20Sopenharmony_ci struct machine *machine, 2118c2ecf20Sopenharmony_ci struct thread *thread, 2128c2ecf20Sopenharmony_ci struct perf_sample *sample, 2138c2ecf20Sopenharmony_ci struct evsel *evsel) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci u64 kernel_start = machine__kernel_start(machine); 2168c2ecf20Sopenharmony_ci struct call_path *current = &dbe->cpr->call_path; 2178c2ecf20Sopenharmony_ci enum chain_order saved_order = callchain_param.order; 2188c2ecf20Sopenharmony_ci int err; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci if (!symbol_conf.use_callchain || !sample->callchain) 2218c2ecf20Sopenharmony_ci return NULL; 2228c2ecf20Sopenharmony_ci 2238c2ecf20Sopenharmony_ci /* 2248c2ecf20Sopenharmony_ci * Since the call path tree must be built starting with the root, we 2258c2ecf20Sopenharmony_ci * must use ORDER_CALL for call chain resolution, in order to process 2268c2ecf20Sopenharmony_ci * the callchain starting with the root node and ending with the leaf. 2278c2ecf20Sopenharmony_ci */ 2288c2ecf20Sopenharmony_ci callchain_param.order = ORDER_CALLER; 2298c2ecf20Sopenharmony_ci err = thread__resolve_callchain(thread, &callchain_cursor, evsel, 2308c2ecf20Sopenharmony_ci sample, NULL, NULL, PERF_MAX_STACK_DEPTH); 2318c2ecf20Sopenharmony_ci if (err) { 2328c2ecf20Sopenharmony_ci callchain_param.order = saved_order; 2338c2ecf20Sopenharmony_ci return NULL; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci callchain_cursor_commit(&callchain_cursor); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci while (1) { 2388c2ecf20Sopenharmony_ci struct callchain_cursor_node *node; 2398c2ecf20Sopenharmony_ci struct addr_location al; 2408c2ecf20Sopenharmony_ci u64 dso_db_id = 0, sym_db_id = 0, offset = 0; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci memset(&al, 0, sizeof(al)); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci node = callchain_cursor_current(&callchain_cursor); 2458c2ecf20Sopenharmony_ci if (!node) 2468c2ecf20Sopenharmony_ci break; 2478c2ecf20Sopenharmony_ci /* 2488c2ecf20Sopenharmony_ci * Handle export of symbol and dso for this node by 2498c2ecf20Sopenharmony_ci * constructing an addr_location struct and then passing it to 2508c2ecf20Sopenharmony_ci * db_ids_from_al() to perform the export. 2518c2ecf20Sopenharmony_ci */ 2528c2ecf20Sopenharmony_ci al.sym = node->ms.sym; 2538c2ecf20Sopenharmony_ci al.map = node->ms.map; 2548c2ecf20Sopenharmony_ci al.maps = thread->maps; 2558c2ecf20Sopenharmony_ci al.addr = node->ip; 2568c2ecf20Sopenharmony_ci 2578c2ecf20Sopenharmony_ci if (al.map && !al.sym) 2588c2ecf20Sopenharmony_ci al.sym = dso__find_symbol(al.map->dso, al.addr); 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci db_ids_from_al(dbe, &al, &dso_db_id, &sym_db_id, &offset); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* add node to the call path tree if it doesn't exist */ 2638c2ecf20Sopenharmony_ci current = call_path__findnew(dbe->cpr, current, 2648c2ecf20Sopenharmony_ci al.sym, node->ip, 2658c2ecf20Sopenharmony_ci kernel_start); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci callchain_cursor_advance(&callchain_cursor); 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* Reset the callchain order to its prior value. */ 2718c2ecf20Sopenharmony_ci callchain_param.order = saved_order; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci if (current == &dbe->cpr->call_path) { 2748c2ecf20Sopenharmony_ci /* Bail because the callchain was empty. */ 2758c2ecf20Sopenharmony_ci return NULL; 2768c2ecf20Sopenharmony_ci } 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci return current; 2798c2ecf20Sopenharmony_ci} 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ciint db_export__branch_type(struct db_export *dbe, u32 branch_type, 2828c2ecf20Sopenharmony_ci const char *name) 2838c2ecf20Sopenharmony_ci{ 2848c2ecf20Sopenharmony_ci if (dbe->export_branch_type) 2858c2ecf20Sopenharmony_ci return dbe->export_branch_type(dbe, branch_type, name); 2868c2ecf20Sopenharmony_ci 2878c2ecf20Sopenharmony_ci return 0; 2888c2ecf20Sopenharmony_ci} 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_cistatic int db_export__threads(struct db_export *dbe, struct thread *thread, 2918c2ecf20Sopenharmony_ci struct thread *main_thread, 2928c2ecf20Sopenharmony_ci struct machine *machine, struct comm **comm_ptr) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct comm *comm = NULL; 2958c2ecf20Sopenharmony_ci struct comm *curr_comm; 2968c2ecf20Sopenharmony_ci int err; 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci if (main_thread) { 2998c2ecf20Sopenharmony_ci /* 3008c2ecf20Sopenharmony_ci * A thread has a reference to the main thread, so export the 3018c2ecf20Sopenharmony_ci * main thread first. 3028c2ecf20Sopenharmony_ci */ 3038c2ecf20Sopenharmony_ci err = db_export__thread(dbe, main_thread, machine, main_thread); 3048c2ecf20Sopenharmony_ci if (err) 3058c2ecf20Sopenharmony_ci return err; 3068c2ecf20Sopenharmony_ci /* 3078c2ecf20Sopenharmony_ci * Export comm before exporting the non-main thread because 3088c2ecf20Sopenharmony_ci * db_export__comm_thread() can be called further below. 3098c2ecf20Sopenharmony_ci */ 3108c2ecf20Sopenharmony_ci comm = machine__thread_exec_comm(machine, main_thread); 3118c2ecf20Sopenharmony_ci if (comm) { 3128c2ecf20Sopenharmony_ci err = db_export__exec_comm(dbe, comm, main_thread); 3138c2ecf20Sopenharmony_ci if (err) 3148c2ecf20Sopenharmony_ci return err; 3158c2ecf20Sopenharmony_ci *comm_ptr = comm; 3168c2ecf20Sopenharmony_ci } 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci if (thread != main_thread) { 3208c2ecf20Sopenharmony_ci /* 3218c2ecf20Sopenharmony_ci * For a non-main thread, db_export__comm_thread() must be 3228c2ecf20Sopenharmony_ci * called only if thread has not previously been exported. 3238c2ecf20Sopenharmony_ci */ 3248c2ecf20Sopenharmony_ci bool export_comm_thread = comm && !thread->db_id; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci err = db_export__thread(dbe, thread, machine, main_thread); 3278c2ecf20Sopenharmony_ci if (err) 3288c2ecf20Sopenharmony_ci return err; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci if (export_comm_thread) { 3318c2ecf20Sopenharmony_ci err = db_export__comm_thread(dbe, comm, thread); 3328c2ecf20Sopenharmony_ci if (err) 3338c2ecf20Sopenharmony_ci return err; 3348c2ecf20Sopenharmony_ci } 3358c2ecf20Sopenharmony_ci } 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci curr_comm = thread__comm(thread); 3388c2ecf20Sopenharmony_ci if (curr_comm) 3398c2ecf20Sopenharmony_ci return db_export__comm(dbe, curr_comm, thread); 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci return 0; 3428c2ecf20Sopenharmony_ci} 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_ciint db_export__sample(struct db_export *dbe, union perf_event *event, 3458c2ecf20Sopenharmony_ci struct perf_sample *sample, struct evsel *evsel, 3468c2ecf20Sopenharmony_ci struct addr_location *al) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci struct thread *thread = al->thread; 3498c2ecf20Sopenharmony_ci struct export_sample es = { 3508c2ecf20Sopenharmony_ci .event = event, 3518c2ecf20Sopenharmony_ci .sample = sample, 3528c2ecf20Sopenharmony_ci .evsel = evsel, 3538c2ecf20Sopenharmony_ci .al = al, 3548c2ecf20Sopenharmony_ci }; 3558c2ecf20Sopenharmony_ci struct thread *main_thread; 3568c2ecf20Sopenharmony_ci struct comm *comm = NULL; 3578c2ecf20Sopenharmony_ci int err; 3588c2ecf20Sopenharmony_ci 3598c2ecf20Sopenharmony_ci err = db_export__evsel(dbe, evsel); 3608c2ecf20Sopenharmony_ci if (err) 3618c2ecf20Sopenharmony_ci return err; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci err = db_export__machine(dbe, al->maps->machine); 3648c2ecf20Sopenharmony_ci if (err) 3658c2ecf20Sopenharmony_ci return err; 3668c2ecf20Sopenharmony_ci 3678c2ecf20Sopenharmony_ci main_thread = thread__main_thread(al->maps->machine, thread); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci err = db_export__threads(dbe, thread, main_thread, al->maps->machine, &comm); 3708c2ecf20Sopenharmony_ci if (err) 3718c2ecf20Sopenharmony_ci goto out_put; 3728c2ecf20Sopenharmony_ci 3738c2ecf20Sopenharmony_ci if (comm) 3748c2ecf20Sopenharmony_ci es.comm_db_id = comm->db_id; 3758c2ecf20Sopenharmony_ci 3768c2ecf20Sopenharmony_ci es.db_id = ++dbe->sample_last_db_id; 3778c2ecf20Sopenharmony_ci 3788c2ecf20Sopenharmony_ci err = db_ids_from_al(dbe, al, &es.dso_db_id, &es.sym_db_id, &es.offset); 3798c2ecf20Sopenharmony_ci if (err) 3808c2ecf20Sopenharmony_ci goto out_put; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci if (dbe->cpr) { 3838c2ecf20Sopenharmony_ci struct call_path *cp = call_path_from_sample(dbe, al->maps->machine, 3848c2ecf20Sopenharmony_ci thread, sample, 3858c2ecf20Sopenharmony_ci evsel); 3868c2ecf20Sopenharmony_ci if (cp) { 3878c2ecf20Sopenharmony_ci db_export__call_path(dbe, cp); 3888c2ecf20Sopenharmony_ci es.call_path_id = cp->db_id; 3898c2ecf20Sopenharmony_ci } 3908c2ecf20Sopenharmony_ci } 3918c2ecf20Sopenharmony_ci 3928c2ecf20Sopenharmony_ci if ((evsel->core.attr.sample_type & PERF_SAMPLE_ADDR) && 3938c2ecf20Sopenharmony_ci sample_addr_correlates_sym(&evsel->core.attr)) { 3948c2ecf20Sopenharmony_ci struct addr_location addr_al; 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci thread__resolve(thread, &addr_al, sample); 3978c2ecf20Sopenharmony_ci err = db_ids_from_al(dbe, &addr_al, &es.addr_dso_db_id, 3988c2ecf20Sopenharmony_ci &es.addr_sym_db_id, &es.addr_offset); 3998c2ecf20Sopenharmony_ci if (err) 4008c2ecf20Sopenharmony_ci goto out_put; 4018c2ecf20Sopenharmony_ci if (dbe->crp) { 4028c2ecf20Sopenharmony_ci err = thread_stack__process(thread, comm, sample, al, 4038c2ecf20Sopenharmony_ci &addr_al, es.db_id, 4048c2ecf20Sopenharmony_ci dbe->crp); 4058c2ecf20Sopenharmony_ci if (err) 4068c2ecf20Sopenharmony_ci goto out_put; 4078c2ecf20Sopenharmony_ci } 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if (dbe->export_sample) 4118c2ecf20Sopenharmony_ci err = dbe->export_sample(dbe, &es); 4128c2ecf20Sopenharmony_ci 4138c2ecf20Sopenharmony_ciout_put: 4148c2ecf20Sopenharmony_ci thread__put(main_thread); 4158c2ecf20Sopenharmony_ci return err; 4168c2ecf20Sopenharmony_ci} 4178c2ecf20Sopenharmony_ci 4188c2ecf20Sopenharmony_cistatic struct { 4198c2ecf20Sopenharmony_ci u32 branch_type; 4208c2ecf20Sopenharmony_ci const char *name; 4218c2ecf20Sopenharmony_ci} branch_types[] = { 4228c2ecf20Sopenharmony_ci {0, "no branch"}, 4238c2ecf20Sopenharmony_ci {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"}, 4248c2ecf20Sopenharmony_ci {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"}, 4258c2ecf20Sopenharmony_ci {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "conditional jump"}, 4268c2ecf20Sopenharmony_ci {PERF_IP_FLAG_BRANCH, "unconditional jump"}, 4278c2ecf20Sopenharmony_ci {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT, 4288c2ecf20Sopenharmony_ci "software interrupt"}, 4298c2ecf20Sopenharmony_ci {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT, 4308c2ecf20Sopenharmony_ci "return from interrupt"}, 4318c2ecf20Sopenharmony_ci {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET, 4328c2ecf20Sopenharmony_ci "system call"}, 4338c2ecf20Sopenharmony_ci {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET, 4348c2ecf20Sopenharmony_ci "return from system call"}, 4358c2ecf20Sopenharmony_ci {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "asynchronous branch"}, 4368c2ecf20Sopenharmony_ci {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC | 4378c2ecf20Sopenharmony_ci PERF_IP_FLAG_INTERRUPT, "hardware interrupt"}, 4388c2ecf20Sopenharmony_ci {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "transaction abort"}, 4398c2ecf20Sopenharmony_ci {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "trace begin"}, 4408c2ecf20Sopenharmony_ci {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "trace end"}, 4418c2ecf20Sopenharmony_ci {0, NULL} 4428c2ecf20Sopenharmony_ci}; 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ciint db_export__branch_types(struct db_export *dbe) 4458c2ecf20Sopenharmony_ci{ 4468c2ecf20Sopenharmony_ci int i, err = 0; 4478c2ecf20Sopenharmony_ci 4488c2ecf20Sopenharmony_ci for (i = 0; branch_types[i].name ; i++) { 4498c2ecf20Sopenharmony_ci err = db_export__branch_type(dbe, branch_types[i].branch_type, 4508c2ecf20Sopenharmony_ci branch_types[i].name); 4518c2ecf20Sopenharmony_ci if (err) 4528c2ecf20Sopenharmony_ci break; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci /* Add trace begin / end variants */ 4568c2ecf20Sopenharmony_ci for (i = 0; branch_types[i].name ; i++) { 4578c2ecf20Sopenharmony_ci const char *name = branch_types[i].name; 4588c2ecf20Sopenharmony_ci u32 type = branch_types[i].branch_type; 4598c2ecf20Sopenharmony_ci char buf[64]; 4608c2ecf20Sopenharmony_ci 4618c2ecf20Sopenharmony_ci if (type == PERF_IP_FLAG_BRANCH || 4628c2ecf20Sopenharmony_ci (type & (PERF_IP_FLAG_TRACE_BEGIN | PERF_IP_FLAG_TRACE_END))) 4638c2ecf20Sopenharmony_ci continue; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "trace begin / %s", name); 4668c2ecf20Sopenharmony_ci err = db_export__branch_type(dbe, type | PERF_IP_FLAG_TRACE_BEGIN, buf); 4678c2ecf20Sopenharmony_ci if (err) 4688c2ecf20Sopenharmony_ci break; 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci snprintf(buf, sizeof(buf), "%s / trace end", name); 4718c2ecf20Sopenharmony_ci err = db_export__branch_type(dbe, type | PERF_IP_FLAG_TRACE_END, buf); 4728c2ecf20Sopenharmony_ci if (err) 4738c2ecf20Sopenharmony_ci break; 4748c2ecf20Sopenharmony_ci } 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci return err; 4778c2ecf20Sopenharmony_ci} 4788c2ecf20Sopenharmony_ci 4798c2ecf20Sopenharmony_ciint db_export__call_path(struct db_export *dbe, struct call_path *cp) 4808c2ecf20Sopenharmony_ci{ 4818c2ecf20Sopenharmony_ci int err; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci if (cp->db_id) 4848c2ecf20Sopenharmony_ci return 0; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_ci if (cp->parent) { 4878c2ecf20Sopenharmony_ci err = db_export__call_path(dbe, cp->parent); 4888c2ecf20Sopenharmony_ci if (err) 4898c2ecf20Sopenharmony_ci return err; 4908c2ecf20Sopenharmony_ci } 4918c2ecf20Sopenharmony_ci 4928c2ecf20Sopenharmony_ci cp->db_id = ++dbe->call_path_last_db_id; 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_ci if (dbe->export_call_path) 4958c2ecf20Sopenharmony_ci return dbe->export_call_path(dbe, cp); 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci return 0; 4988c2ecf20Sopenharmony_ci} 4998c2ecf20Sopenharmony_ci 5008c2ecf20Sopenharmony_ciint db_export__call_return(struct db_export *dbe, struct call_return *cr, 5018c2ecf20Sopenharmony_ci u64 *parent_db_id) 5028c2ecf20Sopenharmony_ci{ 5038c2ecf20Sopenharmony_ci int err; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci err = db_export__call_path(dbe, cr->cp); 5068c2ecf20Sopenharmony_ci if (err) 5078c2ecf20Sopenharmony_ci return err; 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci if (!cr->db_id) 5108c2ecf20Sopenharmony_ci cr->db_id = ++dbe->call_return_last_db_id; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci if (parent_db_id) { 5138c2ecf20Sopenharmony_ci if (!*parent_db_id) 5148c2ecf20Sopenharmony_ci *parent_db_id = ++dbe->call_return_last_db_id; 5158c2ecf20Sopenharmony_ci cr->parent_db_id = *parent_db_id; 5168c2ecf20Sopenharmony_ci } 5178c2ecf20Sopenharmony_ci 5188c2ecf20Sopenharmony_ci if (dbe->export_call_return) 5198c2ecf20Sopenharmony_ci return dbe->export_call_return(dbe, cr); 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci return 0; 5228c2ecf20Sopenharmony_ci} 5238c2ecf20Sopenharmony_ci 5248c2ecf20Sopenharmony_cistatic int db_export__pid_tid(struct db_export *dbe, struct machine *machine, 5258c2ecf20Sopenharmony_ci pid_t pid, pid_t tid, u64 *db_id, 5268c2ecf20Sopenharmony_ci struct comm **comm_ptr, bool *is_idle) 5278c2ecf20Sopenharmony_ci{ 5288c2ecf20Sopenharmony_ci struct thread *thread = machine__find_thread(machine, pid, tid); 5298c2ecf20Sopenharmony_ci struct thread *main_thread; 5308c2ecf20Sopenharmony_ci int err = 0; 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_ci if (!thread || !thread->comm_set) 5338c2ecf20Sopenharmony_ci goto out_put; 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ci *is_idle = !thread->pid_ && !thread->tid; 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci main_thread = thread__main_thread(machine, thread); 5388c2ecf20Sopenharmony_ci 5398c2ecf20Sopenharmony_ci err = db_export__threads(dbe, thread, main_thread, machine, comm_ptr); 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_ci *db_id = thread->db_id; 5428c2ecf20Sopenharmony_ci 5438c2ecf20Sopenharmony_ci thread__put(main_thread); 5448c2ecf20Sopenharmony_ciout_put: 5458c2ecf20Sopenharmony_ci thread__put(thread); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci return err; 5488c2ecf20Sopenharmony_ci} 5498c2ecf20Sopenharmony_ci 5508c2ecf20Sopenharmony_ciint db_export__switch(struct db_export *dbe, union perf_event *event, 5518c2ecf20Sopenharmony_ci struct perf_sample *sample, struct machine *machine) 5528c2ecf20Sopenharmony_ci{ 5538c2ecf20Sopenharmony_ci bool out = event->header.misc & PERF_RECORD_MISC_SWITCH_OUT; 5548c2ecf20Sopenharmony_ci bool out_preempt = out && 5558c2ecf20Sopenharmony_ci (event->header.misc & PERF_RECORD_MISC_SWITCH_OUT_PREEMPT); 5568c2ecf20Sopenharmony_ci int flags = out | (out_preempt << 1); 5578c2ecf20Sopenharmony_ci bool is_idle_a = false, is_idle_b = false; 5588c2ecf20Sopenharmony_ci u64 th_a_id = 0, th_b_id = 0; 5598c2ecf20Sopenharmony_ci u64 comm_out_id, comm_in_id; 5608c2ecf20Sopenharmony_ci struct comm *comm_a = NULL; 5618c2ecf20Sopenharmony_ci struct comm *comm_b = NULL; 5628c2ecf20Sopenharmony_ci u64 th_out_id, th_in_id; 5638c2ecf20Sopenharmony_ci u64 db_id; 5648c2ecf20Sopenharmony_ci int err; 5658c2ecf20Sopenharmony_ci 5668c2ecf20Sopenharmony_ci err = db_export__machine(dbe, machine); 5678c2ecf20Sopenharmony_ci if (err) 5688c2ecf20Sopenharmony_ci return err; 5698c2ecf20Sopenharmony_ci 5708c2ecf20Sopenharmony_ci err = db_export__pid_tid(dbe, machine, sample->pid, sample->tid, 5718c2ecf20Sopenharmony_ci &th_a_id, &comm_a, &is_idle_a); 5728c2ecf20Sopenharmony_ci if (err) 5738c2ecf20Sopenharmony_ci return err; 5748c2ecf20Sopenharmony_ci 5758c2ecf20Sopenharmony_ci if (event->header.type == PERF_RECORD_SWITCH_CPU_WIDE) { 5768c2ecf20Sopenharmony_ci pid_t pid = event->context_switch.next_prev_pid; 5778c2ecf20Sopenharmony_ci pid_t tid = event->context_switch.next_prev_tid; 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci err = db_export__pid_tid(dbe, machine, pid, tid, &th_b_id, 5808c2ecf20Sopenharmony_ci &comm_b, &is_idle_b); 5818c2ecf20Sopenharmony_ci if (err) 5828c2ecf20Sopenharmony_ci return err; 5838c2ecf20Sopenharmony_ci } 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci /* 5868c2ecf20Sopenharmony_ci * Do not export if both threads are unknown (i.e. not being traced), 5878c2ecf20Sopenharmony_ci * or one is unknown and the other is the idle task. 5888c2ecf20Sopenharmony_ci */ 5898c2ecf20Sopenharmony_ci if ((!th_a_id || is_idle_a) && (!th_b_id || is_idle_b)) 5908c2ecf20Sopenharmony_ci return 0; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci db_id = ++dbe->context_switch_last_db_id; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_ci if (out) { 5958c2ecf20Sopenharmony_ci th_out_id = th_a_id; 5968c2ecf20Sopenharmony_ci th_in_id = th_b_id; 5978c2ecf20Sopenharmony_ci comm_out_id = comm_a ? comm_a->db_id : 0; 5988c2ecf20Sopenharmony_ci comm_in_id = comm_b ? comm_b->db_id : 0; 5998c2ecf20Sopenharmony_ci } else { 6008c2ecf20Sopenharmony_ci th_out_id = th_b_id; 6018c2ecf20Sopenharmony_ci th_in_id = th_a_id; 6028c2ecf20Sopenharmony_ci comm_out_id = comm_b ? comm_b->db_id : 0; 6038c2ecf20Sopenharmony_ci comm_in_id = comm_a ? comm_a->db_id : 0; 6048c2ecf20Sopenharmony_ci } 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci if (dbe->export_context_switch) 6078c2ecf20Sopenharmony_ci return dbe->export_context_switch(dbe, db_id, machine, sample, 6088c2ecf20Sopenharmony_ci th_out_id, comm_out_id, 6098c2ecf20Sopenharmony_ci th_in_id, comm_in_id, flags); 6108c2ecf20Sopenharmony_ci return 0; 6118c2ecf20Sopenharmony_ci} 612