Merge tag 'locks-v3.16-2' of git://git.samba.org/jlayton/linux
[linux/fpc-iii.git] / tools / perf / tests / hists_output.c
blobe3bbd6c54c1b023f7f7168ab8ed77dae33c8c8d3
1 #include "perf.h"
2 #include "util/debug.h"
3 #include "util/symbol.h"
4 #include "util/sort.h"
5 #include "util/evsel.h"
6 #include "util/evlist.h"
7 #include "util/machine.h"
8 #include "util/thread.h"
9 #include "util/parse-events.h"
10 #include "tests/tests.h"
11 #include "tests/hists_common.h"
13 struct sample {
14 u32 cpu;
15 u32 pid;
16 u64 ip;
17 struct thread *thread;
18 struct map *map;
19 struct symbol *sym;
22 /* For the numbers, see hists_common.c */
23 static struct sample fake_samples[] = {
24 /* perf [kernel] schedule() */
25 { .cpu = 0, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_KERNEL_SCHEDULE, },
26 /* perf [perf] main() */
27 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_MAIN, },
28 /* perf [perf] cmd_record() */
29 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_PERF_CMD_RECORD, },
30 /* perf [libc] malloc() */
31 { .cpu = 1, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_MALLOC, },
32 /* perf [libc] free() */
33 { .cpu = 2, .pid = FAKE_PID_PERF1, .ip = FAKE_IP_LIBC_FREE, },
34 /* perf [perf] main() */
35 { .cpu = 2, .pid = FAKE_PID_PERF2, .ip = FAKE_IP_PERF_MAIN, },
36 /* perf [kernel] page_fault() */
37 { .cpu = 2, .pid = FAKE_PID_PERF2, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
38 /* bash [bash] main() */
39 { .cpu = 3, .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_MAIN, },
40 /* bash [bash] xmalloc() */
41 { .cpu = 0, .pid = FAKE_PID_BASH, .ip = FAKE_IP_BASH_XMALLOC, },
42 /* bash [kernel] page_fault() */
43 { .cpu = 1, .pid = FAKE_PID_BASH, .ip = FAKE_IP_KERNEL_PAGE_FAULT, },
46 static int add_hist_entries(struct hists *hists, struct machine *machine)
48 struct addr_location al;
49 struct perf_evsel *evsel = hists_to_evsel(hists);
50 struct perf_sample sample = { .period = 100, };
51 size_t i;
53 for (i = 0; i < ARRAY_SIZE(fake_samples); i++) {
54 const union perf_event event = {
55 .header = {
56 .misc = PERF_RECORD_MISC_USER,
59 struct hist_entry_iter iter = {
60 .ops = &hist_iter_normal,
61 .hide_unresolved = false,
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 (perf_event__preprocess_sample(&event, machine, &al,
70 &sample) < 0)
71 goto out;
73 if (hist_entry_iter__add(&iter, &al, evsel, &sample,
74 PERF_MAX_STACK_DEPTH, NULL) < 0)
75 goto out;
77 fake_samples[i].thread = al.thread;
78 fake_samples[i].map = al.map;
79 fake_samples[i].sym = al.sym;
82 return TEST_OK;
84 out:
85 pr_debug("Not enough memory for adding a hist entry\n");
86 return TEST_FAIL;
89 static void del_hist_entries(struct hists *hists)
91 struct hist_entry *he;
92 struct rb_root *root_in;
93 struct rb_root *root_out;
94 struct rb_node *node;
96 if (sort__need_collapse)
97 root_in = &hists->entries_collapsed;
98 else
99 root_in = hists->entries_in;
101 root_out = &hists->entries;
103 while (!RB_EMPTY_ROOT(root_out)) {
104 node = rb_first(root_out);
106 he = rb_entry(node, struct hist_entry, rb_node);
107 rb_erase(node, root_out);
108 rb_erase(&he->rb_node_in, root_in);
109 hist_entry__free(he);
113 typedef int (*test_fn_t)(struct perf_evsel *, struct machine *);
115 #define COMM(he) (thread__comm_str(he->thread))
116 #define DSO(he) (he->ms.map->dso->short_name)
117 #define SYM(he) (he->ms.sym->name)
118 #define CPU(he) (he->cpu)
119 #define PID(he) (he->thread->tid)
121 /* default sort keys (no field) */
122 static int test1(struct perf_evsel *evsel, struct machine *machine)
124 int err;
125 struct hists *hists = &evsel->hists;
126 struct hist_entry *he;
127 struct rb_root *root;
128 struct rb_node *node;
130 field_order = NULL;
131 sort_order = NULL; /* equivalent to sort_order = "comm,dso,sym" */
133 setup_sorting();
136 * expected output:
138 * Overhead Command Shared Object Symbol
139 * ======== ======= ============= ==============
140 * 20.00% perf perf [.] main
141 * 10.00% bash [kernel] [k] page_fault
142 * 10.00% bash bash [.] main
143 * 10.00% bash bash [.] xmalloc
144 * 10.00% perf [kernel] [k] page_fault
145 * 10.00% perf [kernel] [k] schedule
146 * 10.00% perf libc [.] free
147 * 10.00% perf libc [.] malloc
148 * 10.00% perf perf [.] cmd_record
150 err = add_hist_entries(hists, machine);
151 if (err < 0)
152 goto out;
154 hists__collapse_resort(hists, NULL);
155 hists__output_resort(hists);
157 if (verbose > 2) {
158 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
159 print_hists_out(hists);
162 root = &evsel->hists.entries;
163 node = rb_first(root);
164 he = rb_entry(node, struct hist_entry, rb_node);
165 TEST_ASSERT_VAL("Invalid hist entry",
166 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
167 !strcmp(SYM(he), "main") && he->stat.period == 200);
169 node = rb_next(node);
170 he = rb_entry(node, struct hist_entry, rb_node);
171 TEST_ASSERT_VAL("Invalid hist entry",
172 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
173 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
175 node = rb_next(node);
176 he = rb_entry(node, struct hist_entry, rb_node);
177 TEST_ASSERT_VAL("Invalid hist entry",
178 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
179 !strcmp(SYM(he), "main") && he->stat.period == 100);
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), "bash") &&
185 !strcmp(SYM(he), "xmalloc") && he->stat.period == 100);
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), "perf") && !strcmp(DSO(he), "[kernel]") &&
191 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
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), "perf") && !strcmp(DSO(he), "[kernel]") &&
197 !strcmp(SYM(he), "schedule") && he->stat.period == 100);
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), "libc") &&
203 !strcmp(SYM(he), "free") && he->stat.period == 100);
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), "libc") &&
209 !strcmp(SYM(he), "malloc") && he->stat.period == 100);
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), "perf") &&
215 !strcmp(SYM(he), "cmd_record") && he->stat.period == 100);
217 out:
218 del_hist_entries(hists);
219 reset_output_field();
220 return err;
223 /* mixed fields and sort keys */
224 static int test2(struct perf_evsel *evsel, struct machine *machine)
226 int err;
227 struct hists *hists = &evsel->hists;
228 struct hist_entry *he;
229 struct rb_root *root;
230 struct rb_node *node;
232 field_order = "overhead,cpu";
233 sort_order = "pid";
235 setup_sorting();
238 * expected output:
240 * Overhead CPU Command: Pid
241 * ======== === =============
242 * 30.00% 1 perf : 100
243 * 10.00% 0 perf : 100
244 * 10.00% 2 perf : 100
245 * 20.00% 2 perf : 200
246 * 10.00% 0 bash : 300
247 * 10.00% 1 bash : 300
248 * 10.00% 3 bash : 300
250 err = add_hist_entries(hists, machine);
251 if (err < 0)
252 goto out;
254 hists__collapse_resort(hists, NULL);
255 hists__output_resort(hists);
257 if (verbose > 2) {
258 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
259 print_hists_out(hists);
262 root = &evsel->hists.entries;
263 node = rb_first(root);
264 he = rb_entry(node, struct hist_entry, rb_node);
265 TEST_ASSERT_VAL("Invalid hist entry",
266 CPU(he) == 1 && PID(he) == 100 && he->stat.period == 300);
268 node = rb_next(node);
269 he = rb_entry(node, struct hist_entry, rb_node);
270 TEST_ASSERT_VAL("Invalid hist entry",
271 CPU(he) == 0 && PID(he) == 100 && he->stat.period == 100);
273 out:
274 del_hist_entries(hists);
275 reset_output_field();
276 return err;
279 /* fields only (no sort key) */
280 static int test3(struct perf_evsel *evsel, struct machine *machine)
282 int err;
283 struct hists *hists = &evsel->hists;
284 struct hist_entry *he;
285 struct rb_root *root;
286 struct rb_node *node;
288 field_order = "comm,overhead,dso";
289 sort_order = NULL;
291 setup_sorting();
294 * expected output:
296 * Command Overhead Shared Object
297 * ======= ======== =============
298 * bash 20.00% bash
299 * bash 10.00% [kernel]
300 * perf 30.00% perf
301 * perf 20.00% [kernel]
302 * perf 20.00% libc
304 err = add_hist_entries(hists, machine);
305 if (err < 0)
306 goto out;
308 hists__collapse_resort(hists, NULL);
309 hists__output_resort(hists);
311 if (verbose > 2) {
312 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
313 print_hists_out(hists);
316 root = &evsel->hists.entries;
317 node = rb_first(root);
318 he = rb_entry(node, struct hist_entry, rb_node);
319 TEST_ASSERT_VAL("Invalid hist entry",
320 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
321 he->stat.period == 200);
323 node = rb_next(node);
324 he = rb_entry(node, struct hist_entry, rb_node);
325 TEST_ASSERT_VAL("Invalid hist entry",
326 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
327 he->stat.period == 100);
329 node = rb_next(node);
330 he = rb_entry(node, struct hist_entry, rb_node);
331 TEST_ASSERT_VAL("Invalid hist entry",
332 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
333 he->stat.period == 300);
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), "perf") && !strcmp(DSO(he), "[kernel]") &&
339 he->stat.period == 200);
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), "libc") &&
345 he->stat.period == 200);
347 out:
348 del_hist_entries(hists);
349 reset_output_field();
350 return err;
353 /* handle duplicate 'dso' field */
354 static int test4(struct perf_evsel *evsel, struct machine *machine)
356 int err;
357 struct hists *hists = &evsel->hists;
358 struct hist_entry *he;
359 struct rb_root *root;
360 struct rb_node *node;
362 field_order = "dso,sym,comm,overhead,dso";
363 sort_order = "sym";
365 setup_sorting();
368 * expected output:
370 * Shared Object Symbol Command Overhead
371 * ============= ============== ======= ========
372 * perf [.] cmd_record perf 10.00%
373 * libc [.] free perf 10.00%
374 * bash [.] main bash 10.00%
375 * perf [.] main perf 20.00%
376 * libc [.] malloc perf 10.00%
377 * [kernel] [k] page_fault bash 10.00%
378 * [kernel] [k] page_fault perf 10.00%
379 * [kernel] [k] schedule perf 10.00%
380 * bash [.] xmalloc bash 10.00%
382 err = add_hist_entries(hists, machine);
383 if (err < 0)
384 goto out;
386 hists__collapse_resort(hists, NULL);
387 hists__output_resort(hists);
389 if (verbose > 2) {
390 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
391 print_hists_out(hists);
394 root = &evsel->hists.entries;
395 node = rb_first(root);
396 he = rb_entry(node, struct hist_entry, rb_node);
397 TEST_ASSERT_VAL("Invalid hist entry",
398 !strcmp(DSO(he), "perf") && !strcmp(SYM(he), "cmd_record") &&
399 !strcmp(COMM(he), "perf") && he->stat.period == 100);
401 node = rb_next(node);
402 he = rb_entry(node, struct hist_entry, rb_node);
403 TEST_ASSERT_VAL("Invalid hist entry",
404 !strcmp(DSO(he), "libc") && !strcmp(SYM(he), "free") &&
405 !strcmp(COMM(he), "perf") && he->stat.period == 100);
407 node = rb_next(node);
408 he = rb_entry(node, struct hist_entry, rb_node);
409 TEST_ASSERT_VAL("Invalid hist entry",
410 !strcmp(DSO(he), "bash") && !strcmp(SYM(he), "main") &&
411 !strcmp(COMM(he), "bash") && he->stat.period == 100);
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), "perf") && !strcmp(SYM(he), "main") &&
417 !strcmp(COMM(he), "perf") && he->stat.period == 200);
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), "libc") && !strcmp(SYM(he), "malloc") &&
423 !strcmp(COMM(he), "perf") && he->stat.period == 100);
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), "[kernel]") && !strcmp(SYM(he), "page_fault") &&
429 !strcmp(COMM(he), "bash") && he->stat.period == 100);
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), "[kernel]") && !strcmp(SYM(he), "page_fault") &&
435 !strcmp(COMM(he), "perf") && he->stat.period == 100);
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), "schedule") &&
441 !strcmp(COMM(he), "perf") && he->stat.period == 100);
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), "bash") && !strcmp(SYM(he), "xmalloc") &&
447 !strcmp(COMM(he), "bash") && he->stat.period == 100);
449 out:
450 del_hist_entries(hists);
451 reset_output_field();
452 return err;
455 /* full sort keys w/o overhead field */
456 static int test5(struct perf_evsel *evsel, struct machine *machine)
458 int err;
459 struct hists *hists = &evsel->hists;
460 struct hist_entry *he;
461 struct rb_root *root;
462 struct rb_node *node;
464 field_order = "cpu,pid,comm,dso,sym";
465 sort_order = "dso,pid";
467 setup_sorting();
470 * expected output:
472 * CPU Command: Pid Command Shared Object Symbol
473 * === ============= ======= ============= ==============
474 * 0 perf: 100 perf [kernel] [k] schedule
475 * 2 perf: 200 perf [kernel] [k] page_fault
476 * 1 bash: 300 bash [kernel] [k] page_fault
477 * 0 bash: 300 bash bash [.] xmalloc
478 * 3 bash: 300 bash bash [.] main
479 * 1 perf: 100 perf libc [.] malloc
480 * 2 perf: 100 perf libc [.] free
481 * 1 perf: 100 perf perf [.] cmd_record
482 * 1 perf: 100 perf perf [.] main
483 * 2 perf: 200 perf perf [.] main
485 err = add_hist_entries(hists, machine);
486 if (err < 0)
487 goto out;
489 hists__collapse_resort(hists, NULL);
490 hists__output_resort(hists);
492 if (verbose > 2) {
493 pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
494 print_hists_out(hists);
497 root = &evsel->hists.entries;
498 node = rb_first(root);
499 he = rb_entry(node, struct hist_entry, rb_node);
501 TEST_ASSERT_VAL("Invalid hist entry",
502 CPU(he) == 0 && PID(he) == 100 &&
503 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
504 !strcmp(SYM(he), "schedule") && he->stat.period == 100);
506 node = rb_next(node);
507 he = rb_entry(node, struct hist_entry, rb_node);
508 TEST_ASSERT_VAL("Invalid hist entry",
509 CPU(he) == 2 && PID(he) == 200 &&
510 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "[kernel]") &&
511 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
513 node = rb_next(node);
514 he = rb_entry(node, struct hist_entry, rb_node);
515 TEST_ASSERT_VAL("Invalid hist entry",
516 CPU(he) == 1 && PID(he) == 300 &&
517 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "[kernel]") &&
518 !strcmp(SYM(he), "page_fault") && he->stat.period == 100);
520 node = rb_next(node);
521 he = rb_entry(node, struct hist_entry, rb_node);
522 TEST_ASSERT_VAL("Invalid hist entry",
523 CPU(he) == 0 && PID(he) == 300 &&
524 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
525 !strcmp(SYM(he), "xmalloc") && he->stat.period == 100);
527 node = rb_next(node);
528 he = rb_entry(node, struct hist_entry, rb_node);
529 TEST_ASSERT_VAL("Invalid hist entry",
530 CPU(he) == 3 && PID(he) == 300 &&
531 !strcmp(COMM(he), "bash") && !strcmp(DSO(he), "bash") &&
532 !strcmp(SYM(he), "main") && he->stat.period == 100);
534 node = rb_next(node);
535 he = rb_entry(node, struct hist_entry, rb_node);
536 TEST_ASSERT_VAL("Invalid hist entry",
537 CPU(he) == 1 && PID(he) == 100 &&
538 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
539 !strcmp(SYM(he), "malloc") && he->stat.period == 100);
541 node = rb_next(node);
542 he = rb_entry(node, struct hist_entry, rb_node);
543 TEST_ASSERT_VAL("Invalid hist entry",
544 CPU(he) == 2 && PID(he) == 100 &&
545 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "libc") &&
546 !strcmp(SYM(he), "free") && he->stat.period == 100);
548 node = rb_next(node);
549 he = rb_entry(node, struct hist_entry, rb_node);
550 TEST_ASSERT_VAL("Invalid hist entry",
551 CPU(he) == 1 && PID(he) == 100 &&
552 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
553 !strcmp(SYM(he), "cmd_record") && he->stat.period == 100);
555 node = rb_next(node);
556 he = rb_entry(node, struct hist_entry, rb_node);
557 TEST_ASSERT_VAL("Invalid hist entry",
558 CPU(he) == 1 && PID(he) == 100 &&
559 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
560 !strcmp(SYM(he), "main") && he->stat.period == 100);
562 node = rb_next(node);
563 he = rb_entry(node, struct hist_entry, rb_node);
564 TEST_ASSERT_VAL("Invalid hist entry",
565 CPU(he) == 2 && PID(he) == 200 &&
566 !strcmp(COMM(he), "perf") && !strcmp(DSO(he), "perf") &&
567 !strcmp(SYM(he), "main") && he->stat.period == 100);
569 out:
570 del_hist_entries(hists);
571 reset_output_field();
572 return err;
575 int test__hists_output(void)
577 int err = TEST_FAIL;
578 struct machines machines;
579 struct machine *machine;
580 struct perf_evsel *evsel;
581 struct perf_evlist *evlist = perf_evlist__new();
582 size_t i;
583 test_fn_t testcases[] = {
584 test1,
585 test2,
586 test3,
587 test4,
588 test5,
591 TEST_ASSERT_VAL("No memory", evlist);
593 err = parse_events(evlist, "cpu-clock");
594 if (err)
595 goto out;
597 machines__init(&machines);
599 /* setup threads/dso/map/symbols also */
600 machine = setup_fake_machine(&machines);
601 if (!machine)
602 goto out;
604 if (verbose > 1)
605 machine__fprintf(machine, stderr);
607 evsel = perf_evlist__first(evlist);
609 for (i = 0; i < ARRAY_SIZE(testcases); i++) {
610 err = testcases[i](evsel, machine);
611 if (err < 0)
612 break;
615 out:
616 /* tear down everything */
617 perf_evlist__delete(evlist);
618 machines__exit(&machines);
620 return err;