18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci#include <inttypes.h> 38c2ecf20Sopenharmony_ci#include "util/debug.h" 48c2ecf20Sopenharmony_ci#include "util/dso.h" 58c2ecf20Sopenharmony_ci#include "util/event.h" // struct perf_sample 68c2ecf20Sopenharmony_ci#include "util/map.h" 78c2ecf20Sopenharmony_ci#include "util/symbol.h" 88c2ecf20Sopenharmony_ci#include "util/sort.h" 98c2ecf20Sopenharmony_ci#include "util/evsel.h" 108c2ecf20Sopenharmony_ci#include "util/machine.h" 118c2ecf20Sopenharmony_ci#include "util/thread.h" 128c2ecf20Sopenharmony_ci#include "tests/hists_common.h" 138c2ecf20Sopenharmony_ci#include <linux/kernel.h> 148c2ecf20Sopenharmony_ci#include <linux/perf_event.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_cistatic struct { 178c2ecf20Sopenharmony_ci u32 pid; 188c2ecf20Sopenharmony_ci const char *comm; 198c2ecf20Sopenharmony_ci} fake_threads[] = { 208c2ecf20Sopenharmony_ci { FAKE_PID_PERF1, "perf" }, 218c2ecf20Sopenharmony_ci { FAKE_PID_PERF2, "perf" }, 228c2ecf20Sopenharmony_ci { FAKE_PID_BASH, "bash" }, 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistatic struct { 268c2ecf20Sopenharmony_ci u32 pid; 278c2ecf20Sopenharmony_ci u64 start; 288c2ecf20Sopenharmony_ci const char *filename; 298c2ecf20Sopenharmony_ci} fake_mmap_info[] = { 308c2ecf20Sopenharmony_ci { FAKE_PID_PERF1, FAKE_MAP_PERF, "perf" }, 318c2ecf20Sopenharmony_ci { FAKE_PID_PERF1, FAKE_MAP_LIBC, "libc" }, 328c2ecf20Sopenharmony_ci { FAKE_PID_PERF1, FAKE_MAP_KERNEL, "[kernel]" }, 338c2ecf20Sopenharmony_ci { FAKE_PID_PERF2, FAKE_MAP_PERF, "perf" }, 348c2ecf20Sopenharmony_ci { FAKE_PID_PERF2, FAKE_MAP_LIBC, "libc" }, 358c2ecf20Sopenharmony_ci { FAKE_PID_PERF2, FAKE_MAP_KERNEL, "[kernel]" }, 368c2ecf20Sopenharmony_ci { FAKE_PID_BASH, FAKE_MAP_BASH, "bash" }, 378c2ecf20Sopenharmony_ci { FAKE_PID_BASH, FAKE_MAP_LIBC, "libc" }, 388c2ecf20Sopenharmony_ci { FAKE_PID_BASH, FAKE_MAP_KERNEL, "[kernel]" }, 398c2ecf20Sopenharmony_ci}; 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistruct fake_sym { 428c2ecf20Sopenharmony_ci u64 start; 438c2ecf20Sopenharmony_ci u64 length; 448c2ecf20Sopenharmony_ci const char *name; 458c2ecf20Sopenharmony_ci}; 468c2ecf20Sopenharmony_ci 478c2ecf20Sopenharmony_cistatic struct fake_sym perf_syms[] = { 488c2ecf20Sopenharmony_ci { FAKE_SYM_OFFSET1, FAKE_SYM_LENGTH, "main" }, 498c2ecf20Sopenharmony_ci { FAKE_SYM_OFFSET2, FAKE_SYM_LENGTH, "run_command" }, 508c2ecf20Sopenharmony_ci { FAKE_SYM_OFFSET3, FAKE_SYM_LENGTH, "cmd_record" }, 518c2ecf20Sopenharmony_ci}; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_cistatic struct fake_sym bash_syms[] = { 548c2ecf20Sopenharmony_ci { FAKE_SYM_OFFSET1, FAKE_SYM_LENGTH, "main" }, 558c2ecf20Sopenharmony_ci { FAKE_SYM_OFFSET2, FAKE_SYM_LENGTH, "xmalloc" }, 568c2ecf20Sopenharmony_ci { FAKE_SYM_OFFSET3, FAKE_SYM_LENGTH, "xfree" }, 578c2ecf20Sopenharmony_ci}; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_cistatic struct fake_sym libc_syms[] = { 608c2ecf20Sopenharmony_ci { 700, 100, "malloc" }, 618c2ecf20Sopenharmony_ci { 800, 100, "free" }, 628c2ecf20Sopenharmony_ci { 900, 100, "realloc" }, 638c2ecf20Sopenharmony_ci { FAKE_SYM_OFFSET1, FAKE_SYM_LENGTH, "malloc" }, 648c2ecf20Sopenharmony_ci { FAKE_SYM_OFFSET2, FAKE_SYM_LENGTH, "free" }, 658c2ecf20Sopenharmony_ci { FAKE_SYM_OFFSET3, FAKE_SYM_LENGTH, "realloc" }, 668c2ecf20Sopenharmony_ci}; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_cistatic struct fake_sym kernel_syms[] = { 698c2ecf20Sopenharmony_ci { FAKE_SYM_OFFSET1, FAKE_SYM_LENGTH, "schedule" }, 708c2ecf20Sopenharmony_ci { FAKE_SYM_OFFSET2, FAKE_SYM_LENGTH, "page_fault" }, 718c2ecf20Sopenharmony_ci { FAKE_SYM_OFFSET3, FAKE_SYM_LENGTH, "sys_perf_event_open" }, 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic struct { 758c2ecf20Sopenharmony_ci const char *dso_name; 768c2ecf20Sopenharmony_ci struct fake_sym *syms; 778c2ecf20Sopenharmony_ci size_t nr_syms; 788c2ecf20Sopenharmony_ci} fake_symbols[] = { 798c2ecf20Sopenharmony_ci { "perf", perf_syms, ARRAY_SIZE(perf_syms) }, 808c2ecf20Sopenharmony_ci { "bash", bash_syms, ARRAY_SIZE(bash_syms) }, 818c2ecf20Sopenharmony_ci { "libc", libc_syms, ARRAY_SIZE(libc_syms) }, 828c2ecf20Sopenharmony_ci { "[kernel]", kernel_syms, ARRAY_SIZE(kernel_syms) }, 838c2ecf20Sopenharmony_ci}; 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_cistruct machine *setup_fake_machine(struct machines *machines) 868c2ecf20Sopenharmony_ci{ 878c2ecf20Sopenharmony_ci struct machine *machine = machines__find(machines, HOST_KERNEL_ID); 888c2ecf20Sopenharmony_ci size_t i; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ci if (machine == NULL) { 918c2ecf20Sopenharmony_ci pr_debug("Not enough memory for machine setup\n"); 928c2ecf20Sopenharmony_ci return NULL; 938c2ecf20Sopenharmony_ci } 948c2ecf20Sopenharmony_ci 958c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(fake_threads); i++) { 968c2ecf20Sopenharmony_ci struct thread *thread; 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci thread = machine__findnew_thread(machine, fake_threads[i].pid, 998c2ecf20Sopenharmony_ci fake_threads[i].pid); 1008c2ecf20Sopenharmony_ci if (thread == NULL) 1018c2ecf20Sopenharmony_ci goto out; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci thread__set_comm(thread, fake_threads[i].comm, 0); 1048c2ecf20Sopenharmony_ci thread__put(thread); 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(fake_mmap_info); i++) { 1088c2ecf20Sopenharmony_ci struct perf_sample sample = { 1098c2ecf20Sopenharmony_ci .cpumode = PERF_RECORD_MISC_USER, 1108c2ecf20Sopenharmony_ci }; 1118c2ecf20Sopenharmony_ci union perf_event fake_mmap_event = { 1128c2ecf20Sopenharmony_ci .mmap = { 1138c2ecf20Sopenharmony_ci .pid = fake_mmap_info[i].pid, 1148c2ecf20Sopenharmony_ci .tid = fake_mmap_info[i].pid, 1158c2ecf20Sopenharmony_ci .start = fake_mmap_info[i].start, 1168c2ecf20Sopenharmony_ci .len = FAKE_MAP_LENGTH, 1178c2ecf20Sopenharmony_ci .pgoff = 0ULL, 1188c2ecf20Sopenharmony_ci }, 1198c2ecf20Sopenharmony_ci }; 1208c2ecf20Sopenharmony_ci 1218c2ecf20Sopenharmony_ci strcpy(fake_mmap_event.mmap.filename, 1228c2ecf20Sopenharmony_ci fake_mmap_info[i].filename); 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_ci machine__process_mmap_event(machine, &fake_mmap_event, &sample); 1258c2ecf20Sopenharmony_ci } 1268c2ecf20Sopenharmony_ci 1278c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(fake_symbols); i++) { 1288c2ecf20Sopenharmony_ci size_t k; 1298c2ecf20Sopenharmony_ci struct dso *dso; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci dso = machine__findnew_dso(machine, fake_symbols[i].dso_name); 1328c2ecf20Sopenharmony_ci if (dso == NULL) 1338c2ecf20Sopenharmony_ci goto out; 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci /* emulate dso__load() */ 1368c2ecf20Sopenharmony_ci dso__set_loaded(dso); 1378c2ecf20Sopenharmony_ci 1388c2ecf20Sopenharmony_ci for (k = 0; k < fake_symbols[i].nr_syms; k++) { 1398c2ecf20Sopenharmony_ci struct symbol *sym; 1408c2ecf20Sopenharmony_ci struct fake_sym *fsym = &fake_symbols[i].syms[k]; 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci sym = symbol__new(fsym->start, fsym->length, 1438c2ecf20Sopenharmony_ci STB_GLOBAL, STT_FUNC, fsym->name); 1448c2ecf20Sopenharmony_ci if (sym == NULL) { 1458c2ecf20Sopenharmony_ci dso__put(dso); 1468c2ecf20Sopenharmony_ci goto out; 1478c2ecf20Sopenharmony_ci } 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci symbols__insert(&dso->symbols, sym); 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci dso__put(dso); 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_ci return machine; 1568c2ecf20Sopenharmony_ci 1578c2ecf20Sopenharmony_ciout: 1588c2ecf20Sopenharmony_ci pr_debug("Not enough memory for machine setup\n"); 1598c2ecf20Sopenharmony_ci machine__delete_threads(machine); 1608c2ecf20Sopenharmony_ci return NULL; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_civoid print_hists_in(struct hists *hists) 1648c2ecf20Sopenharmony_ci{ 1658c2ecf20Sopenharmony_ci int i = 0; 1668c2ecf20Sopenharmony_ci struct rb_root_cached *root; 1678c2ecf20Sopenharmony_ci struct rb_node *node; 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci if (hists__has(hists, need_collapse)) 1708c2ecf20Sopenharmony_ci root = &hists->entries_collapsed; 1718c2ecf20Sopenharmony_ci else 1728c2ecf20Sopenharmony_ci root = hists->entries_in; 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci pr_info("----- %s --------\n", __func__); 1758c2ecf20Sopenharmony_ci node = rb_first_cached(root); 1768c2ecf20Sopenharmony_ci while (node) { 1778c2ecf20Sopenharmony_ci struct hist_entry *he; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci he = rb_entry(node, struct hist_entry, rb_node_in); 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci if (!he->filtered) { 1828c2ecf20Sopenharmony_ci pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n", 1838c2ecf20Sopenharmony_ci i, thread__comm_str(he->thread), 1848c2ecf20Sopenharmony_ci he->ms.map->dso->short_name, 1858c2ecf20Sopenharmony_ci he->ms.sym->name, he->stat.period); 1868c2ecf20Sopenharmony_ci } 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_ci i++; 1898c2ecf20Sopenharmony_ci node = rb_next(node); 1908c2ecf20Sopenharmony_ci } 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_civoid print_hists_out(struct hists *hists) 1948c2ecf20Sopenharmony_ci{ 1958c2ecf20Sopenharmony_ci int i = 0; 1968c2ecf20Sopenharmony_ci struct rb_root_cached *root; 1978c2ecf20Sopenharmony_ci struct rb_node *node; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci root = &hists->entries; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci pr_info("----- %s --------\n", __func__); 2028c2ecf20Sopenharmony_ci node = rb_first_cached(root); 2038c2ecf20Sopenharmony_ci while (node) { 2048c2ecf20Sopenharmony_ci struct hist_entry *he; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci he = rb_entry(node, struct hist_entry, rb_node); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci if (!he->filtered) { 2098c2ecf20Sopenharmony_ci pr_info("%2d: entry: %8s:%5d [%-8s] %20s: period = %"PRIu64"/%"PRIu64"\n", 2108c2ecf20Sopenharmony_ci i, thread__comm_str(he->thread), he->thread->tid, 2118c2ecf20Sopenharmony_ci he->ms.map->dso->short_name, 2128c2ecf20Sopenharmony_ci he->ms.sym->name, he->stat.period, 2138c2ecf20Sopenharmony_ci he->stat_acc ? he->stat_acc->period : 0); 2148c2ecf20Sopenharmony_ci } 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci i++; 2178c2ecf20Sopenharmony_ci node = rb_next(node); 2188c2ecf20Sopenharmony_ci } 2198c2ecf20Sopenharmony_ci} 220