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