2 #include "util/debug.h"
3 #include "util/event.h"
4 #include "util/symbol.h"
6 #include "util/evsel.h"
7 #include "util/evlist.h"
8 #include "util/machine.h"
9 #include "util/thread.h"
10 #include "util/parse-events.h"
11 #include "tests/tests.h"
12 #include "tests/hists_common.h"
13 #include <linux/kernel.h>
19 struct thread *thread;
24 /* For the numbers, see hists_common.c */
25 static struct sample fake_samples[] = {
26 /* perf [kernel] schedule() */
27 { .cpu = 0, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
28 /* perf [perf] main() */
29 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, },
30 /* perf [perf] cmd_record() */
31 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_CMD_RECORD, },
32 /* perf [libc] malloc() */
33 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
34 /* perf [libc] free() */
35 { .cpu = 2, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_FREE, },
36 /* perf [perf] main() */
37 { .cpu = 2, .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },
38 /* perf [kernel] page_fault() */
39 { .cpu = 2, .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
40 /* bash [bash] main() */
41 { .cpu = 3, .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, },
42 /* bash [bash] xmalloc() */
43 { .cpu = 0, .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
44 /* bash [kernel] page_fault() */
45 { .cpu = 1, .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
48 static int add_hist_entries(struct hists *hists, struct machine *machine)
50 struct addr_location al;
51 struct perf_evsel *evsel = hists_to_evsel(hists);
52 struct perf_sample sample = { .period = 100, };
55 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
56 struct hist_entry_iter iter = {
59 .ops = &hist_iter_normal,
60 .hide_unresolved = false,
63 sample.cpumode = PERF_RECORD_MISC_USER;
64 sample.cpu = fake_samples[i].cpu;
65 sample.pid = fake_samples[i].pid;
66 sample.tid = fake_samples[i].pid;
67 sample.ip = fake_samples[i].ip;
69 if (machine__resolve(machine, &al, &sample) < 0)
72 if (hist_entry_iter__add(&iter, &al, sysctl_perf_event_max_stack,
74 addr_location__put(&al);
78 fake_samples[i].thread = al.thread;
79 fake_samples[i].map = al.map;
80 fake_samples[i].sym = al.sym;
86 pr_debug("Not enough memory for adding a hist entry\n");
90 static void del_hist_entries(struct hists *hists)
92 struct hist_entry *he;
93 struct rb_root *root_in;
94 struct rb_root *root_out;
97 if (hists__has(hists, need_collapse))
98 root_in = &hists->entries_collapsed;
100 root_in = hists->entries_in;
102 root_out = &hists->entries;
104 while (!RB_EMPTY_ROOT(root_out)) {
105 node = rb_first(root_out);
107 he = rb_entry(node, struct hist_entry, rb_node);
108 rb_erase(node, root_out);
109 rb_erase(&he->rb_node_in, root_in);
110 hist_entry__delete(he);
114 typedef int (*test_fn_t)(struct perf_evsel *, struct machine *);
116 #define COMM(he) (thread__comm_str(he->thread))
117 #define DSO(he) (he->ms.map->dso->short_name)
118 #define SYM(he) (he->ms.sym->name)
119 #define CPU(he) (he->cpu)
120 #define PID(he) (he->thread->tid)
122 /* default sort keys (no field) */
123 static int test1(struct perf_evsel *evsel, struct machine *machine)
126 struct hists *hists = evsel__hists(evsel);
127 struct hist_entry *he;
128 struct rb_root *root;
129 struct rb_node *node;
132 sort_order = NULL; /* equivalent to sort_order = "comm,dso,sym" */
139 * Overhead Command Shared Object Symbol
140 * ======== ======= ============= ==============
141 * 20.00% perf perf [.] main
142 * 10.00% bash [kernel] [k] page_fault
143 * 10.00% bash bash [.] main
144 * 10.00% bash bash [.] xmalloc
145 * 10.00% perf [kernel] [k] page_fault
146 * 10.00% perf [kernel] [k] schedule
147 * 10.00% perf libc [.] free
148 * 10.00% perf libc [.] malloc
149 * 10.00% perf perf [.] cmd_record
151 err = add_hist_entries(hists, machine);
155 hists__collapse_resort(hists, NULL);
156 perf_evsel__output_resort(evsel, NULL);
159 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
160 print_hists_out(hists);
163 root = &hists->entries;
164 node = rb_first(root);
165 he = rb_entry(node, struct hist_entry, rb_node);
166 TEST_ASSERT_VAL("Invalid hist entry",
167 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
168 !strcmp(SYM(he), "main") && he->stat.period == 200);
170 node = rb_next(node);
171 he = rb_entry(node, struct hist_entry, rb_node);
172 TEST_ASSERT_VAL("Invalid hist entry",
173 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
174 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
176 node = rb_next(node);
177 he = rb_entry(node, struct hist_entry, rb_node);
178 TEST_ASSERT_VAL("Invalid hist entry",
179 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
180 !strcmp(SYM(he), "main") && he->stat.period == 100);
182 node = rb_next(node);
183 he = rb_entry(node, struct hist_entry, rb_node);
184 TEST_ASSERT_VAL("Invalid hist entry",
185 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
186 !strcmp(SYM(he), "xmalloc") && he->stat.period == 100);
188 node = rb_next(node);
189 he = rb_entry(node, struct hist_entry, rb_node);
190 TEST_ASSERT_VAL("Invalid hist entry",
191 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
192 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
194 node = rb_next(node);
195 he = rb_entry(node, struct hist_entry, rb_node);
196 TEST_ASSERT_VAL("Invalid hist entry",
197 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
198 !strcmp(SYM(he), "schedule") && he->stat.period == 100);
200 node = rb_next(node);
201 he = rb_entry(node, struct hist_entry, rb_node);
202 TEST_ASSERT_VAL("Invalid hist entry",
203 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
204 !strcmp(SYM(he), "free") && he->stat.period == 100);
206 node = rb_next(node);
207 he = rb_entry(node, struct hist_entry, rb_node);
208 TEST_ASSERT_VAL("Invalid hist entry",
209 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
210 !strcmp(SYM(he), "malloc") && he->stat.period == 100);
212 node = rb_next(node);
213 he = rb_entry(node, struct hist_entry, rb_node);
214 TEST_ASSERT_VAL("Invalid hist entry",
215 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
216 !strcmp(SYM(he), "cmd_record") && he->stat.period == 100);
219 del_hist_entries(hists);
220 reset_output_field();
224 /* mixed fields and sort keys */
225 static int test2(struct perf_evsel *evsel, struct machine *machine)
228 struct hists *hists = evsel__hists(evsel);
229 struct hist_entry *he;
230 struct rb_root *root;
231 struct rb_node *node;
233 field_order = "overhead,cpu";
241 * Overhead CPU Command: Pid
242 * ======== === =============
243 * 30.00% 1 perf : 100
244 * 10.00% 0 perf : 100
245 * 10.00% 2 perf : 100
246 * 20.00% 2 perf : 200
247 * 10.00% 0 bash : 300
248 * 10.00% 1 bash : 300
249 * 10.00% 3 bash : 300
251 err = add_hist_entries(hists, machine);
255 hists__collapse_resort(hists, NULL);
256 perf_evsel__output_resort(evsel, NULL);
259 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
260 print_hists_out(hists);
263 root = &hists->entries;
264 node = rb_first(root);
265 he = rb_entry(node, struct hist_entry, rb_node);
266 TEST_ASSERT_VAL("Invalid hist entry",
267 CPU(he) == 1 && PID(he) == 100 && he->stat.period == 300);
269 node = rb_next(node);
270 he = rb_entry(node, struct hist_entry, rb_node);
271 TEST_ASSERT_VAL("Invalid hist entry",
272 CPU(he) == 0 && PID(he) == 100 && he->stat.period == 100);
275 del_hist_entries(hists);
276 reset_output_field();
280 /* fields only (no sort key) */
281 static int test3(struct perf_evsel *evsel, struct machine *machine)
284 struct hists *hists = evsel__hists(evsel);
285 struct hist_entry *he;
286 struct rb_root *root;
287 struct rb_node *node;
289 field_order = "comm,overhead,dso";
297 * Command Overhead Shared Object
298 * ======= ======== =============
300 * bash 10.00% [kernel]
302 * perf 20.00% [kernel]
305 err = add_hist_entries(hists, machine);
309 hists__collapse_resort(hists, NULL);
310 perf_evsel__output_resort(evsel, NULL);
313 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
314 print_hists_out(hists);
317 root = &hists->entries;
318 node = rb_first(root);
319 he = rb_entry(node, struct hist_entry, rb_node);
320 TEST_ASSERT_VAL("Invalid hist entry",
321 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
322 he->stat.period == 200);
324 node = rb_next(node);
325 he = rb_entry(node, struct hist_entry, rb_node);
326 TEST_ASSERT_VAL("Invalid hist entry",
327 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
328 he->stat.period == 100);
330 node = rb_next(node);
331 he = rb_entry(node, struct hist_entry, rb_node);
332 TEST_ASSERT_VAL("Invalid hist entry",
333 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
334 he->stat.period == 300);
336 node = rb_next(node);
337 he = rb_entry(node, struct hist_entry, rb_node);
338 TEST_ASSERT_VAL("Invalid hist entry",
339 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
340 he->stat.period == 200);
342 node = rb_next(node);
343 he = rb_entry(node, struct hist_entry, rb_node);
344 TEST_ASSERT_VAL("Invalid hist entry",
345 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
346 he->stat.period == 200);
349 del_hist_entries(hists);
350 reset_output_field();
354 /* handle duplicate 'dso' field */
355 static int test4(struct perf_evsel *evsel, struct machine *machine)
358 struct hists *hists = evsel__hists(evsel);
359 struct hist_entry *he;
360 struct rb_root *root;
361 struct rb_node *node;
363 field_order = "dso,sym,comm,overhead,dso";
371 * Shared Object Symbol Command Overhead
372 * ============= ============== ======= ========
373 * perf [.] cmd_record perf 10.00%
374 * libc [.] free perf 10.00%
375 * bash [.] main bash 10.00%
376 * perf [.] main perf 20.00%
377 * libc [.] malloc perf 10.00%
378 * [kernel] [k] page_fault bash 10.00%
379 * [kernel] [k] page_fault perf 10.00%
380 * [kernel] [k] schedule perf 10.00%
381 * bash [.] xmalloc bash 10.00%
383 err = add_hist_entries(hists, machine);
387 hists__collapse_resort(hists, NULL);
388 perf_evsel__output_resort(evsel, NULL);
391 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
392 print_hists_out(hists);
395 root = &hists->entries;
396 node = rb_first(root);
397 he = rb_entry(node, struct hist_entry, rb_node);
398 TEST_ASSERT_VAL("Invalid hist entry",
399 !strcmp(DSO(he), "perf") && !strcmp(SYM(he), "cmd_record") &&
400 !strcmp(COMM(he), "perf") && he->stat.period == 100);
402 node = rb_next(node);
403 he = rb_entry(node, struct hist_entry, rb_node);
404 TEST_ASSERT_VAL("Invalid hist entry",
405 !strcmp(DSO(he), "libc") && !strcmp(SYM(he), "free") &&
406 !strcmp(COMM(he), "perf") && he->stat.period == 100);
408 node = rb_next(node);
409 he = rb_entry(node, struct hist_entry, rb_node);
410 TEST_ASSERT_VAL("Invalid hist entry",
411 !strcmp(DSO(he), "bash") && !strcmp(SYM(he), "main") &&
412 !strcmp(COMM(he), "bash") && he->stat.period == 100);
414 node = rb_next(node);
415 he = rb_entry(node, struct hist_entry, rb_node);
416 TEST_ASSERT_VAL("Invalid hist entry",
417 !strcmp(DSO(he), "perf") && !strcmp(SYM(he), "main") &&
418 !strcmp(COMM(he), "perf") && he->stat.period == 200);
420 node = rb_next(node);
421 he = rb_entry(node, struct hist_entry, rb_node);
422 TEST_ASSERT_VAL("Invalid hist entry",
423 !strcmp(DSO(he), "libc") && !strcmp(SYM(he), "malloc") &&
424 !strcmp(COMM(he), "perf") && he->stat.period == 100);
426 node = rb_next(node);
427 he = rb_entry(node, struct hist_entry, rb_node);
428 TEST_ASSERT_VAL("Invalid hist entry",
429 !strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "page_fault") &&
430 !strcmp(COMM(he), "bash") && he->stat.period == 100);
432 node = rb_next(node);
433 he = rb_entry(node, struct hist_entry, rb_node);
434 TEST_ASSERT_VAL("Invalid hist entry",
435 !strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "page_fault") &&
436 !strcmp(COMM(he), "perf") && he->stat.period == 100);
438 node = rb_next(node);
439 he = rb_entry(node, struct hist_entry, rb_node);
440 TEST_ASSERT_VAL("Invalid hist entry",
441 !strcmp(DSO(he), "[kernel]") && !strcmp(SYM(he), "schedule") &&
442 !strcmp(COMM(he), "perf") && he->stat.period == 100);
444 node = rb_next(node);
445 he = rb_entry(node, struct hist_entry, rb_node);
446 TEST_ASSERT_VAL("Invalid hist entry",
447 !strcmp(DSO(he), "bash") && !strcmp(SYM(he), "xmalloc") &&
448 !strcmp(COMM(he), "bash") && he->stat.period == 100);
451 del_hist_entries(hists);
452 reset_output_field();
456 /* full sort keys w/o overhead field */
457 static int test5(struct perf_evsel *evsel, struct machine *machine)
460 struct hists *hists = evsel__hists(evsel);
461 struct hist_entry *he;
462 struct rb_root *root;
463 struct rb_node *node;
465 field_order = "cpu,pid,comm,dso,sym";
466 sort_order = "dso,pid";
473 * CPU Command: Pid Command Shared Object Symbol
474 * === ============= ======= ============= ==============
475 * 0 perf: 100 perf [kernel] [k] schedule
476 * 2 perf: 200 perf [kernel] [k] page_fault
477 * 1 bash: 300 bash [kernel] [k] page_fault
478 * 0 bash: 300 bash bash [.] xmalloc
479 * 3 bash: 300 bash bash [.] main
480 * 1 perf: 100 perf libc [.] malloc
481 * 2 perf: 100 perf libc [.] free
482 * 1 perf: 100 perf perf [.] cmd_record
483 * 1 perf: 100 perf perf [.] main
484 * 2 perf: 200 perf perf [.] main
486 err = add_hist_entries(hists, machine);
490 hists__collapse_resort(hists, NULL);
491 perf_evsel__output_resort(evsel, NULL);
494 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
495 print_hists_out(hists);
498 root = &hists->entries;
499 node = rb_first(root);
500 he = rb_entry(node, struct hist_entry, rb_node);
502 TEST_ASSERT_VAL("Invalid hist entry",
503 CPU(he) == 0 && PID(he) == 100 &&
504 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
505 !strcmp(SYM(he), "schedule") && he->stat.period == 100);
507 node = rb_next(node);
508 he = rb_entry(node, struct hist_entry, rb_node);
509 TEST_ASSERT_VAL("Invalid hist entry",
510 CPU(he) == 2 && PID(he) == 200 &&
511 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
512 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
514 node = rb_next(node);
515 he = rb_entry(node, struct hist_entry, rb_node);
516 TEST_ASSERT_VAL("Invalid hist entry",
517 CPU(he) == 1 && PID(he) == 300 &&
518 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
519 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
521 node = rb_next(node);
522 he = rb_entry(node, struct hist_entry, rb_node);
523 TEST_ASSERT_VAL("Invalid hist entry",
524 CPU(he) == 0 && PID(he) == 300 &&
525 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
526 !strcmp(SYM(he), "xmalloc") && he->stat.period == 100);
528 node = rb_next(node);
529 he = rb_entry(node, struct hist_entry, rb_node);
530 TEST_ASSERT_VAL("Invalid hist entry",
531 CPU(he) == 3 && PID(he) == 300 &&
532 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
533 !strcmp(SYM(he), "main") && he->stat.period == 100);
535 node = rb_next(node);
536 he = rb_entry(node, struct hist_entry, rb_node);
537 TEST_ASSERT_VAL("Invalid hist entry",
538 CPU(he) == 1 && PID(he) == 100 &&
539 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
540 !strcmp(SYM(he), "malloc") && he->stat.period == 100);
542 node = rb_next(node);
543 he = rb_entry(node, struct hist_entry, rb_node);
544 TEST_ASSERT_VAL("Invalid hist entry",
545 CPU(he) == 2 && PID(he) == 100 &&
546 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
547 !strcmp(SYM(he), "free") && he->stat.period == 100);
549 node = rb_next(node);
550 he = rb_entry(node, struct hist_entry, rb_node);
551 TEST_ASSERT_VAL("Invalid hist entry",
552 CPU(he) == 1 && PID(he) == 100 &&
553 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
554 !strcmp(SYM(he), "cmd_record") && he->stat.period == 100);
556 node = rb_next(node);
557 he = rb_entry(node, struct hist_entry, rb_node);
558 TEST_ASSERT_VAL("Invalid hist entry",
559 CPU(he) == 1 && PID(he) == 100 &&
560 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
561 !strcmp(SYM(he), "main") && he->stat.period == 100);
563 node = rb_next(node);
564 he = rb_entry(node, struct hist_entry, rb_node);
565 TEST_ASSERT_VAL("Invalid hist entry",
566 CPU(he) == 2 && PID(he) == 200 &&
567 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
568 !strcmp(SYM(he), "main") && he->stat.period == 100);
571 del_hist_entries(hists);
572 reset_output_field();
576 int test__hists_output(int subtest __maybe_unused)
579 struct machines machines;
580 struct machine *machine;
581 struct perf_evsel *evsel;
582 struct perf_evlist *evlist = perf_evlist__new();
584 test_fn_t testcases[] = {
592 TEST_ASSERT_VAL("No memory", evlist);
594 err = parse_events(evlist, "cpu-clock", NULL);
599 machines__init(&machines);
601 /* setup threads/dso/map/symbols also */
602 machine = setup_fake_machine(&machines);
607 machine__fprintf(machine, stderr);
609 evsel = perf_evlist__first(evlist);
611 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
612 err = testcases[i](evsel, machine);
618 /* tear down everything */
619 perf_evlist__delete(evlist);
620 machines__exit(&machines);