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