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