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