brintos

brintos / linux-shallow public Read only

0
0
Text · 18.4 KiB · 33b5cc8 Raw
642 lines · c
1// SPDX-License-Identifier: GPL-2.02#include "util/debug.h"3#include "util/dso.h"4#include "util/event.h"5#include "util/map.h"6#include "util/symbol.h"7#include "util/sort.h"8#include "util/evsel.h"9#include "util/evlist.h"10#include "util/machine.h"11#include "util/thread.h"12#include "util/parse-events.h"13#include "tests/tests.h"14#include "tests/hists_common.h"15#include <linux/kernel.h>16 17struct sample {18	u32 cpu;19	u32 pid;20	u64 ip;21	struct thread *thread;22	struct map *map;23	struct symbol *sym;24};25 26/* For the numbers, see hists_common.c */27static struct sample fake_samples[] = {28	/* perf [kernel] schedule() */29	{ .cpu = 0, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },30	/* perf [perf]   main() */31	{ .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, },32	/* perf [perf]   cmd_record() */33	{ .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_CMD_RECORD, },34	/* perf [libc]   malloc() */35	{ .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },36	/* perf [libc]   free() */37	{ .cpu = 2, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_FREE, },38	/* perf [perf]   main() */39	{ .cpu = 2, .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },40	/* perf [kernel] page_fault() */41	{ .cpu = 2, .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },42	/* bash [bash]   main() */43	{ .cpu = 3, .pid = FAKE_PID_BASH,  .ip = FAKE_IP_BASH_MAIN, },44	/* bash [bash]   xmalloc() */45	{ .cpu = 0, .pid = FAKE_PID_BASH,  .ip = FAKE_IP_BASH_XMALLOC, },46	/* bash [kernel] page_fault() */47	{ .cpu = 1, .pid = FAKE_PID_BASH,  .ip = FAKE_IP_KERNEL_PAGE_FAULT, },48};49 50static int add_hist_entries(struct hists *hists, struct machine *machine)51{52	struct addr_location al;53	struct evsel *evsel = hists_to_evsel(hists);54	struct perf_sample sample = { .period = 100, };55	size_t i;56 57	addr_location__init(&al);58	for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {59		struct hist_entry_iter iter = {60			.evsel = evsel,61			.sample = &sample,62			.ops = &hist_iter_normal,63			.hide_unresolved = false,64		};65 66		sample.cpumode = PERF_RECORD_MISC_USER;67		sample.cpu = fake_samples[i].cpu;68		sample.pid = fake_samples[i].pid;69		sample.tid = fake_samples[i].pid;70		sample.ip = fake_samples[i].ip;71 72		if (machine__resolve(machine, &al, &sample) < 0)73			goto out;74 75		if (hist_entry_iter__add(&iter, &al, sysctl_perf_event_max_stack,76					 NULL) < 0) {77			goto out;78		}79 80		fake_samples[i].thread = al.thread;81		map__put(fake_samples[i].map);82		fake_samples[i].map = map__get(al.map);83		fake_samples[i].sym = al.sym;84	}85 86	addr_location__exit(&al);87	return TEST_OK;88 89out:90	pr_debug("Not enough memory for adding a hist entry\n");91	addr_location__exit(&al);92	return TEST_FAIL;93}94 95static void del_hist_entries(struct hists *hists)96{97	struct hist_entry *he;98	struct rb_root_cached *root_in;99	struct rb_root_cached *root_out;100	struct rb_node *node;101 102	if (hists__has(hists, need_collapse))103		root_in = &hists->entries_collapsed;104	else105		root_in = hists->entries_in;106 107	root_out = &hists->entries;108 109	while (!RB_EMPTY_ROOT(&root_out->rb_root)) {110		node = rb_first_cached(root_out);111 112		he = rb_entry(node, struct hist_entry, rb_node);113		rb_erase_cached(node, root_out);114		rb_erase_cached(&he->rb_node_in, root_in);115		hist_entry__delete(he);116	}117}118 119static void put_fake_samples(void)120{121	size_t i;122 123	for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {124		map__put(fake_samples[i].map);125		fake_samples[i].map = NULL;126	}127}128 129typedef int (*test_fn_t)(struct evsel *, struct machine *);130 131#define COMM(he)  (thread__comm_str(he->thread))132#define DSO(he)   (dso__short_name(map__dso(he->ms.map)))133#define SYM(he)   (he->ms.sym->name)134#define CPU(he)   (he->cpu)135#define PID(he)   (thread__tid(he->thread))136 137/* default sort keys (no field) */138static int test1(struct evsel *evsel, struct machine *machine)139{140	int err;141	struct hists *hists = evsel__hists(evsel);142	struct hist_entry *he;143	struct rb_root_cached *root;144	struct rb_node *node;145 146	field_order = NULL;147	sort_order = NULL; /* equivalent to sort_order = "comm,dso,sym" */148 149	setup_sorting(NULL);150 151	/*152	 * expected output:153	 *154	 * Overhead  Command  Shared Object          Symbol155	 * ========  =======  =============  ==============156	 *   20.00%     perf  perf           [.] main157	 *   10.00%     bash  [kernel]       [k] page_fault158	 *   10.00%     bash  bash           [.] main159	 *   10.00%     bash  bash           [.] xmalloc160	 *   10.00%     perf  [kernel]       [k] page_fault161	 *   10.00%     perf  [kernel]       [k] schedule162	 *   10.00%     perf  libc           [.] free163	 *   10.00%     perf  libc           [.] malloc164	 *   10.00%     perf  perf           [.] cmd_record165	 */166	err = add_hist_entries(hists, machine);167	if (err < 0)168		goto out;169 170	hists__collapse_resort(hists, NULL);171	evsel__output_resort(evsel, NULL);172 173	if (verbose > 2) {174		pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);175		print_hists_out(hists);176	}177 178	root = &hists->entries;179	node = rb_first_cached(root);180	he = rb_entry(node, struct hist_entry, rb_node);181	TEST_ASSERT_VAL("Invalid hist entry",182			!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&183			!strcmp(SYM(he), "main") && he->stat.period == 200);184 185	node = rb_next(node);186	he = rb_entry(node, struct hist_entry, rb_node);187	TEST_ASSERT_VAL("Invalid hist entry",188			!strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&189			!strcmp(SYM(he), "page_fault") && he->stat.period == 100);190 191	node = rb_next(node);192	he = rb_entry(node, struct hist_entry, rb_node);193	TEST_ASSERT_VAL("Invalid hist entry",194			!strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&195			!strcmp(SYM(he), "main") && he->stat.period == 100);196 197	node = rb_next(node);198	he = rb_entry(node, struct hist_entry, rb_node);199	TEST_ASSERT_VAL("Invalid hist entry",200			!strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&201			!strcmp(SYM(he), "xmalloc") && he->stat.period == 100);202 203	node = rb_next(node);204	he = rb_entry(node, struct hist_entry, rb_node);205	TEST_ASSERT_VAL("Invalid hist entry",206			!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&207			!strcmp(SYM(he), "page_fault") && he->stat.period == 100);208 209	node = rb_next(node);210	he = rb_entry(node, struct hist_entry, rb_node);211	TEST_ASSERT_VAL("Invalid hist entry",212			!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&213			!strcmp(SYM(he), "schedule") && he->stat.period == 100);214 215	node = rb_next(node);216	he = rb_entry(node, struct hist_entry, rb_node);217	TEST_ASSERT_VAL("Invalid hist entry",218			!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&219			!strcmp(SYM(he), "free") && he->stat.period == 100);220 221	node = rb_next(node);222	he = rb_entry(node, struct hist_entry, rb_node);223	TEST_ASSERT_VAL("Invalid hist entry",224			!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&225			!strcmp(SYM(he), "malloc") && he->stat.period == 100);226 227	node = rb_next(node);228	he = rb_entry(node, struct hist_entry, rb_node);229	TEST_ASSERT_VAL("Invalid hist entry",230			!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&231			!strcmp(SYM(he), "cmd_record") && he->stat.period == 100);232 233out:234	del_hist_entries(hists);235	reset_output_field();236	return err;237}238 239/* mixed fields and sort keys */240static int test2(struct evsel *evsel, struct machine *machine)241{242	int err;243	struct hists *hists = evsel__hists(evsel);244	struct hist_entry *he;245	struct rb_root_cached *root;246	struct rb_node *node;247 248	field_order = "overhead,cpu";249	sort_order = "pid";250 251	setup_sorting(NULL);252 253	/*254	 * expected output:255	 *256	 * Overhead  CPU  Command:  Pid257	 * ========  ===  =============258	 *   30.00%    1  perf   :  100259	 *   10.00%    0  perf   :  100260	 *   10.00%    2  perf   :  100261	 *   20.00%    2  perf   :  200262	 *   10.00%    0  bash   :  300263	 *   10.00%    1  bash   :  300264	 *   10.00%    3  bash   :  300265	 */266	err = add_hist_entries(hists, machine);267	if (err < 0)268		goto out;269 270	hists__collapse_resort(hists, NULL);271	evsel__output_resort(evsel, NULL);272 273	if (verbose > 2) {274		pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);275		print_hists_out(hists);276	}277 278	root = &hists->entries;279	node = rb_first_cached(root);280	he = rb_entry(node, struct hist_entry, rb_node);281	TEST_ASSERT_VAL("Invalid hist entry",282			CPU(he) == 1 && PID(he) == 100 && he->stat.period == 300);283 284	node = rb_next(node);285	he = rb_entry(node, struct hist_entry, rb_node);286	TEST_ASSERT_VAL("Invalid hist entry",287			CPU(he) == 0 && PID(he) == 100 && he->stat.period == 100);288 289out:290	del_hist_entries(hists);291	reset_output_field();292	return err;293}294 295/* fields only (no sort key) */296static int test3(struct evsel *evsel, struct machine *machine)297{298	int err;299	struct hists *hists = evsel__hists(evsel);300	struct hist_entry *he;301	struct rb_root_cached *root;302	struct rb_node *node;303 304	field_order = "comm,overhead,dso";305	sort_order = NULL;306 307	setup_sorting(NULL);308 309	/*310	 * expected output:311	 *312	 * Command  Overhead  Shared Object313	 * =======  ========  =============314	 *    bash    20.00%  bash315	 *    bash    10.00%  [kernel]316	 *    perf    30.00%  perf317	 *    perf    20.00%  [kernel]318	 *    perf    20.00%  libc319	 */320	err = add_hist_entries(hists, machine);321	if (err < 0)322		goto out;323 324	hists__collapse_resort(hists, NULL);325	evsel__output_resort(evsel, NULL);326 327	if (verbose > 2) {328		pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);329		print_hists_out(hists);330	}331 332	root = &hists->entries;333	node = rb_first_cached(root);334	he = rb_entry(node, struct hist_entry, rb_node);335	TEST_ASSERT_VAL("Invalid hist entry",336			!strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&337			he->stat.period == 200);338 339	node = rb_next(node);340	he = rb_entry(node, struct hist_entry, rb_node);341	TEST_ASSERT_VAL("Invalid hist entry",342			!strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&343			he->stat.period == 100);344 345	node = rb_next(node);346	he = rb_entry(node, struct hist_entry, rb_node);347	TEST_ASSERT_VAL("Invalid hist entry",348			!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&349			he->stat.period == 300);350 351	node = rb_next(node);352	he = rb_entry(node, struct hist_entry, rb_node);353	TEST_ASSERT_VAL("Invalid hist entry",354			!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&355			he->stat.period == 200);356 357	node = rb_next(node);358	he = rb_entry(node, struct hist_entry, rb_node);359	TEST_ASSERT_VAL("Invalid hist entry",360			!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&361			he->stat.period == 200);362 363out:364	del_hist_entries(hists);365	reset_output_field();366	return err;367}368 369/* handle duplicate 'dso' field */370static int test4(struct evsel *evsel, struct machine *machine)371{372	int err;373	struct hists *hists = evsel__hists(evsel);374	struct hist_entry *he;375	struct rb_root_cached *root;376	struct rb_node *node;377 378	field_order = "dso,sym,comm,overhead,dso";379	sort_order = "sym";380 381	setup_sorting(NULL);382 383	/*384	 * expected output:385	 *386	 * Shared Object          Symbol  Command  Overhead387	 * =============  ==============  =======  ========388	 *          perf  [.] cmd_record     perf    10.00%389	 *          libc  [.] free           perf    10.00%390	 *          bash  [.] main           bash    10.00%391	 *          perf  [.] main           perf    20.00%392	 *          libc  [.] malloc         perf    10.00%393	 *      [kernel]  [k] page_fault     bash    10.00%394	 *      [kernel]  [k] page_fault     perf    10.00%395	 *      [kernel]  [k] schedule       perf    10.00%396	 *          bash  [.] xmalloc        bash    10.00%397	 */398	err = add_hist_entries(hists, machine);399	if (err < 0)400		goto out;401 402	hists__collapse_resort(hists, NULL);403	evsel__output_resort(evsel, NULL);404 405	if (verbose > 2) {406		pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);407		print_hists_out(hists);408	}409 410	root = &hists->entries;411	node = rb_first_cached(root);412	he = rb_entry(node, struct hist_entry, rb_node);413	TEST_ASSERT_VAL("Invalid hist entry",414			!strcmp(DSO(he), "perf") && !strcmp(SYM(he), "cmd_record") &&415			!strcmp(COMM(he), "perf") && he->stat.period == 100);416 417	node = rb_next(node);418	he = rb_entry(node, struct hist_entry, rb_node);419	TEST_ASSERT_VAL("Invalid hist entry",420			!strcmp(DSO(he), "libc") && !strcmp(SYM(he), "free") &&421			!strcmp(COMM(he), "perf") && he->stat.period == 100);422 423	node = rb_next(node);424	he = rb_entry(node, struct hist_entry, rb_node);425	TEST_ASSERT_VAL("Invalid hist entry",426			!strcmp(DSO(he), "bash") && !strcmp(SYM(he), "main") &&427			!strcmp(COMM(he), "bash") && he->stat.period == 100);428 429	node = rb_next(node);430	he = rb_entry(node, struct hist_entry, rb_node);431	TEST_ASSERT_VAL("Invalid hist entry",432			!strcmp(DSO(he), "perf") && !strcmp(SYM(he), "main") &&433			!strcmp(COMM(he), "perf") && he->stat.period == 200);434 435	node = rb_next(node);436	he = rb_entry(node, struct hist_entry, rb_node);437	TEST_ASSERT_VAL("Invalid hist entry",438			!strcmp(DSO(he), "libc") && !strcmp(SYM(he), "malloc") &&439			!strcmp(COMM(he), "perf") && he->stat.period == 100);440 441	node = rb_next(node);442	he = rb_entry(node, struct hist_entry, rb_node);443	TEST_ASSERT_VAL("Invalid hist entry",444			!strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "page_fault") &&445			!strcmp(COMM(he), "bash") && he->stat.period == 100);446 447	node = rb_next(node);448	he = rb_entry(node, struct hist_entry, rb_node);449	TEST_ASSERT_VAL("Invalid hist entry",450			!strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "page_fault") &&451			!strcmp(COMM(he), "perf") && he->stat.period == 100);452 453	node = rb_next(node);454	he = rb_entry(node, struct hist_entry, rb_node);455	TEST_ASSERT_VAL("Invalid hist entry",456			!strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "schedule") &&457			!strcmp(COMM(he), "perf") && he->stat.period == 100);458 459	node = rb_next(node);460	he = rb_entry(node, struct hist_entry, rb_node);461	TEST_ASSERT_VAL("Invalid hist entry",462			!strcmp(DSO(he), "bash") && !strcmp(SYM(he), "xmalloc") &&463			!strcmp(COMM(he), "bash") && he->stat.period == 100);464 465out:466	del_hist_entries(hists);467	reset_output_field();468	return err;469}470 471/* full sort keys w/o overhead field */472static int test5(struct evsel *evsel, struct machine *machine)473{474	int err;475	struct hists *hists = evsel__hists(evsel);476	struct hist_entry *he;477	struct rb_root_cached *root;478	struct rb_node *node;479 480	field_order = "cpu,pid,comm,dso,sym";481	sort_order = "dso,pid";482 483	setup_sorting(NULL);484 485	/*486	 * expected output:487	 *488	 * CPU  Command:  Pid  Command  Shared Object          Symbol489	 * ===  =============  =======  =============  ==============490	 *   0     perf:  100     perf       [kernel]  [k] schedule491	 *   2     perf:  200     perf       [kernel]  [k] page_fault492	 *   1     bash:  300     bash       [kernel]  [k] page_fault493	 *   0     bash:  300     bash           bash  [.] xmalloc494	 *   3     bash:  300     bash           bash  [.] main495	 *   1     perf:  100     perf           libc  [.] malloc496	 *   2     perf:  100     perf           libc  [.] free497	 *   1     perf:  100     perf           perf  [.] cmd_record498	 *   1     perf:  100     perf           perf  [.] main499	 *   2     perf:  200     perf           perf  [.] main500	 */501	err = add_hist_entries(hists, machine);502	if (err < 0)503		goto out;504 505	hists__collapse_resort(hists, NULL);506	evsel__output_resort(evsel, NULL);507 508	if (verbose > 2) {509		pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);510		print_hists_out(hists);511	}512 513	root = &hists->entries;514	node = rb_first_cached(root);515	he = rb_entry(node, struct hist_entry, rb_node);516 517	TEST_ASSERT_VAL("Invalid hist entry",518			CPU(he) == 0 && PID(he) == 100 &&519			!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&520			!strcmp(SYM(he), "schedule") && he->stat.period == 100);521 522	node = rb_next(node);523	he = rb_entry(node, struct hist_entry, rb_node);524	TEST_ASSERT_VAL("Invalid hist entry",525			CPU(he) == 2 && PID(he) == 200 &&526			!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&527			!strcmp(SYM(he), "page_fault") && he->stat.period == 100);528 529	node = rb_next(node);530	he = rb_entry(node, struct hist_entry, rb_node);531	TEST_ASSERT_VAL("Invalid hist entry",532			CPU(he) == 1 && PID(he) == 300 &&533			!strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&534			!strcmp(SYM(he), "page_fault") && he->stat.period == 100);535 536	node = rb_next(node);537	he = rb_entry(node, struct hist_entry, rb_node);538	TEST_ASSERT_VAL("Invalid hist entry",539			CPU(he) == 0 && PID(he) == 300 &&540			!strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&541			!strcmp(SYM(he), "xmalloc") && he->stat.period == 100);542 543	node = rb_next(node);544	he = rb_entry(node, struct hist_entry, rb_node);545	TEST_ASSERT_VAL("Invalid hist entry",546			CPU(he) == 3 && PID(he) == 300 &&547			!strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&548			!strcmp(SYM(he), "main") && he->stat.period == 100);549 550	node = rb_next(node);551	he = rb_entry(node, struct hist_entry, rb_node);552	TEST_ASSERT_VAL("Invalid hist entry",553			CPU(he) == 1 && PID(he) == 100 &&554			!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&555			!strcmp(SYM(he), "malloc") && he->stat.period == 100);556 557	node = rb_next(node);558	he = rb_entry(node, struct hist_entry, rb_node);559	TEST_ASSERT_VAL("Invalid hist entry",560			CPU(he) == 2 && PID(he) == 100 &&561			!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&562			!strcmp(SYM(he), "free") && he->stat.period == 100);563 564	node = rb_next(node);565	he = rb_entry(node, struct hist_entry, rb_node);566	TEST_ASSERT_VAL("Invalid hist entry",567			CPU(he) == 1 && PID(he) == 100 &&568			!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&569			!strcmp(SYM(he), "cmd_record") && he->stat.period == 100);570 571	node = rb_next(node);572	he = rb_entry(node, struct hist_entry, rb_node);573	TEST_ASSERT_VAL("Invalid hist entry",574			CPU(he) == 1 && PID(he) == 100 &&575			!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&576			!strcmp(SYM(he), "main") && he->stat.period == 100);577 578	node = rb_next(node);579	he = rb_entry(node, struct hist_entry, rb_node);580	TEST_ASSERT_VAL("Invalid hist entry",581			CPU(he) == 2 && PID(he) == 200 &&582			!strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&583			!strcmp(SYM(he), "main") && he->stat.period == 100);584 585out:586	del_hist_entries(hists);587	reset_output_field();588	return err;589}590 591static int test__hists_output(struct test_suite *test __maybe_unused, int subtest __maybe_unused)592{593	int err = TEST_FAIL;594	struct machines machines;595	struct machine *machine;596	struct evsel *evsel;597	struct evlist *evlist = evlist__new();598	size_t i;599	test_fn_t testcases[] = {600		test1,601		test2,602		test3,603		test4,604		test5,605	};606 607	TEST_ASSERT_VAL("No memory", evlist);608 609	err = parse_event(evlist, "cpu-clock");610	if (err)611		goto out;612	err = TEST_FAIL;613 614	machines__init(&machines);615 616	/* setup threads/dso/map/symbols also */617	machine = setup_fake_machine(&machines);618	if (!machine)619		goto out;620 621	if (verbose > 1)622		machine__fprintf(machine, stderr);623 624	evsel = evlist__first(evlist);625 626	for (i = 0; i < ARRAY_SIZE(testcases); i++) {627		err = testcases[i](evsel, machine);628		if (err < 0)629			break;630	}631 632out:633	/* tear down everything */634	evlist__delete(evlist);635	machines__exit(&machines);636	put_fake_samples();637 638	return err;639}640 641DEFINE_SUITE("Sort output of hist entries", hists_output);642