Merge branch 'x86-build-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[cascardo/linux.git] / tools / perf / builtin-diff.c
1 /*
2  * builtin-diff.c
3  *
4  * Builtin diff command: Analyze two perf.data input files, look up and read
5  * DSOs and symbol information, sort them and produce a diff.
6  */
7 #include "builtin.h"
8
9 #include "util/debug.h"
10 #include "util/event.h"
11 #include "util/hist.h"
12 #include "util/evsel.h"
13 #include "util/evlist.h"
14 #include "util/session.h"
15 #include "util/tool.h"
16 #include "util/sort.h"
17 #include "util/symbol.h"
18 #include "util/util.h"
19 #include "util/data.h"
20
21 #include <stdlib.h>
22 #include <math.h>
23
24 /* Diff command specific HPP columns. */
25 enum {
26         PERF_HPP_DIFF__BASELINE,
27         PERF_HPP_DIFF__PERIOD,
28         PERF_HPP_DIFF__PERIOD_BASELINE,
29         PERF_HPP_DIFF__DELTA,
30         PERF_HPP_DIFF__RATIO,
31         PERF_HPP_DIFF__WEIGHTED_DIFF,
32         PERF_HPP_DIFF__FORMULA,
33
34         PERF_HPP_DIFF__MAX_INDEX
35 };
36
37 struct diff_hpp_fmt {
38         struct perf_hpp_fmt      fmt;
39         int                      idx;
40         char                    *header;
41         int                      header_width;
42 };
43
44 struct data__file {
45         struct perf_session     *session;
46         struct perf_data_file   file;
47         int                      idx;
48         struct hists            *hists;
49         struct diff_hpp_fmt      fmt[PERF_HPP_DIFF__MAX_INDEX];
50 };
51
52 static struct data__file *data__files;
53 static int data__files_cnt;
54
55 #define data__for_each_file_start(i, d, s)      \
56         for (i = s, d = &data__files[s];        \
57              i < data__files_cnt;               \
58              i++, d = &data__files[i])
59
60 #define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
61 #define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
62
63 static char diff__default_sort_order[] = "dso,symbol";
64 static bool force;
65 static bool show_period;
66 static bool show_formula;
67 static bool show_baseline_only;
68 static unsigned int sort_compute;
69
70 static s64 compute_wdiff_w1;
71 static s64 compute_wdiff_w2;
72
73 enum {
74         COMPUTE_DELTA,
75         COMPUTE_RATIO,
76         COMPUTE_WEIGHTED_DIFF,
77         COMPUTE_MAX,
78 };
79
80 const char *compute_names[COMPUTE_MAX] = {
81         [COMPUTE_DELTA] = "delta",
82         [COMPUTE_RATIO] = "ratio",
83         [COMPUTE_WEIGHTED_DIFF] = "wdiff",
84 };
85
86 static int compute;
87
88 static int compute_2_hpp[COMPUTE_MAX] = {
89         [COMPUTE_DELTA]         = PERF_HPP_DIFF__DELTA,
90         [COMPUTE_RATIO]         = PERF_HPP_DIFF__RATIO,
91         [COMPUTE_WEIGHTED_DIFF] = PERF_HPP_DIFF__WEIGHTED_DIFF,
92 };
93
94 #define MAX_COL_WIDTH 70
95
96 static struct header_column {
97         const char *name;
98         int width;
99 } columns[PERF_HPP_DIFF__MAX_INDEX] = {
100         [PERF_HPP_DIFF__BASELINE] = {
101                 .name  = "Baseline",
102         },
103         [PERF_HPP_DIFF__PERIOD] = {
104                 .name  = "Period",
105                 .width = 14,
106         },
107         [PERF_HPP_DIFF__PERIOD_BASELINE] = {
108                 .name  = "Base period",
109                 .width = 14,
110         },
111         [PERF_HPP_DIFF__DELTA] = {
112                 .name  = "Delta",
113                 .width = 7,
114         },
115         [PERF_HPP_DIFF__RATIO] = {
116                 .name  = "Ratio",
117                 .width = 14,
118         },
119         [PERF_HPP_DIFF__WEIGHTED_DIFF] = {
120                 .name  = "Weighted diff",
121                 .width = 14,
122         },
123         [PERF_HPP_DIFF__FORMULA] = {
124                 .name  = "Formula",
125                 .width = MAX_COL_WIDTH,
126         }
127 };
128
129 static int setup_compute_opt_wdiff(char *opt)
130 {
131         char *w1_str = opt;
132         char *w2_str;
133
134         int ret = -EINVAL;
135
136         if (!opt)
137                 goto out;
138
139         w2_str = strchr(opt, ',');
140         if (!w2_str)
141                 goto out;
142
143         *w2_str++ = 0x0;
144         if (!*w2_str)
145                 goto out;
146
147         compute_wdiff_w1 = strtol(w1_str, NULL, 10);
148         compute_wdiff_w2 = strtol(w2_str, NULL, 10);
149
150         if (!compute_wdiff_w1 || !compute_wdiff_w2)
151                 goto out;
152
153         pr_debug("compute wdiff w1(%" PRId64 ") w2(%" PRId64 ")\n",
154                   compute_wdiff_w1, compute_wdiff_w2);
155
156         ret = 0;
157
158  out:
159         if (ret)
160                 pr_err("Failed: wrong weight data, use 'wdiff:w1,w2'\n");
161
162         return ret;
163 }
164
165 static int setup_compute_opt(char *opt)
166 {
167         if (compute == COMPUTE_WEIGHTED_DIFF)
168                 return setup_compute_opt_wdiff(opt);
169
170         if (opt) {
171                 pr_err("Failed: extra option specified '%s'", opt);
172                 return -EINVAL;
173         }
174
175         return 0;
176 }
177
178 static int setup_compute(const struct option *opt, const char *str,
179                          int unset __maybe_unused)
180 {
181         int *cp = (int *) opt->value;
182         char *cstr = (char *) str;
183         char buf[50];
184         unsigned i;
185         char *option;
186
187         if (!str) {
188                 *cp = COMPUTE_DELTA;
189                 return 0;
190         }
191
192         option = strchr(str, ':');
193         if (option) {
194                 unsigned len = option++ - str;
195
196                 /*
197                  * The str data are not writeable, so we need
198                  * to use another buffer.
199                  */
200
201                 /* No option value is longer. */
202                 if (len >= sizeof(buf))
203                         return -EINVAL;
204
205                 strncpy(buf, str, len);
206                 buf[len] = 0x0;
207                 cstr = buf;
208         }
209
210         for (i = 0; i < COMPUTE_MAX; i++)
211                 if (!strcmp(cstr, compute_names[i])) {
212                         *cp = i;
213                         return setup_compute_opt(option);
214                 }
215
216         pr_err("Failed: '%s' is not computation method "
217                "(use 'delta','ratio' or 'wdiff')\n", str);
218         return -EINVAL;
219 }
220
221 static double period_percent(struct hist_entry *he, u64 period)
222 {
223         u64 total = he->hists->stats.total_period;
224         return (period * 100.0) / total;
225 }
226
227 static double compute_delta(struct hist_entry *he, struct hist_entry *pair)
228 {
229         double old_percent = period_percent(he, he->stat.period);
230         double new_percent = period_percent(pair, pair->stat.period);
231
232         pair->diff.period_ratio_delta = new_percent - old_percent;
233         pair->diff.computed = true;
234         return pair->diff.period_ratio_delta;
235 }
236
237 static double compute_ratio(struct hist_entry *he, struct hist_entry *pair)
238 {
239         double old_period = he->stat.period ?: 1;
240         double new_period = pair->stat.period;
241
242         pair->diff.computed = true;
243         pair->diff.period_ratio = new_period / old_period;
244         return pair->diff.period_ratio;
245 }
246
247 static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
248 {
249         u64 old_period = he->stat.period;
250         u64 new_period = pair->stat.period;
251
252         pair->diff.computed = true;
253         pair->diff.wdiff = new_period * compute_wdiff_w2 -
254                            old_period * compute_wdiff_w1;
255
256         return pair->diff.wdiff;
257 }
258
259 static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
260                          char *buf, size_t size)
261 {
262         return scnprintf(buf, size,
263                          "(%" PRIu64 " * 100 / %" PRIu64 ") - "
264                          "(%" PRIu64 " * 100 / %" PRIu64 ")",
265                           pair->stat.period, pair->hists->stats.total_period,
266                           he->stat.period, he->hists->stats.total_period);
267 }
268
269 static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
270                          char *buf, size_t size)
271 {
272         double old_period = he->stat.period;
273         double new_period = pair->stat.period;
274
275         return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
276 }
277
278 static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
279                          char *buf, size_t size)
280 {
281         u64 old_period = he->stat.period;
282         u64 new_period = pair->stat.period;
283
284         return scnprintf(buf, size,
285                   "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
286                   new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
287 }
288
289 static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
290                            char *buf, size_t size)
291 {
292         switch (compute) {
293         case COMPUTE_DELTA:
294                 return formula_delta(he, pair, buf, size);
295         case COMPUTE_RATIO:
296                 return formula_ratio(he, pair, buf, size);
297         case COMPUTE_WEIGHTED_DIFF:
298                 return formula_wdiff(he, pair, buf, size);
299         default:
300                 BUG_ON(1);
301         }
302
303         return -1;
304 }
305
306 static int hists__add_entry(struct hists *hists,
307                             struct addr_location *al, u64 period,
308                             u64 weight, u64 transaction)
309 {
310         if (__hists__add_entry(hists, al, NULL, NULL, NULL, period, weight,
311                                transaction) != NULL)
312                 return 0;
313         return -ENOMEM;
314 }
315
316 static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
317                                       union perf_event *event,
318                                       struct perf_sample *sample,
319                                       struct perf_evsel *evsel,
320                                       struct machine *machine)
321 {
322         struct addr_location al;
323
324         if (perf_event__preprocess_sample(event, machine, &al, sample) < 0) {
325                 pr_warning("problem processing %d event, skipping it.\n",
326                            event->header.type);
327                 return -1;
328         }
329
330         if (al.filtered)
331                 return 0;
332
333         if (hists__add_entry(&evsel->hists, &al, sample->period,
334                              sample->weight, sample->transaction)) {
335                 pr_warning("problem incrementing symbol period, skipping event\n");
336                 return -1;
337         }
338
339         evsel->hists.stats.total_period += sample->period;
340         return 0;
341 }
342
343 static struct perf_tool tool = {
344         .sample = diff__process_sample_event,
345         .mmap   = perf_event__process_mmap,
346         .comm   = perf_event__process_comm,
347         .exit   = perf_event__process_exit,
348         .fork   = perf_event__process_fork,
349         .lost   = perf_event__process_lost,
350         .ordered_samples = true,
351         .ordering_requires_timestamps = true,
352 };
353
354 static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
355                                       struct perf_evlist *evlist)
356 {
357         struct perf_evsel *e;
358
359         evlist__for_each(evlist, e) {
360                 if (perf_evsel__match2(evsel, e))
361                         return e;
362         }
363
364         return NULL;
365 }
366
367 static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
368 {
369         struct perf_evsel *evsel;
370
371         evlist__for_each(evlist, evsel) {
372                 struct hists *hists = &evsel->hists;
373
374                 hists__collapse_resort(hists, NULL);
375         }
376 }
377
378 static struct hist_entry*
379 get_pair_data(struct hist_entry *he, struct data__file *d)
380 {
381         if (hist_entry__has_pairs(he)) {
382                 struct hist_entry *pair;
383
384                 list_for_each_entry(pair, &he->pairs.head, pairs.node)
385                         if (pair->hists == d->hists)
386                                 return pair;
387         }
388
389         return NULL;
390 }
391
392 static struct hist_entry*
393 get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt)
394 {
395         void *ptr = dfmt - dfmt->idx;
396         struct data__file *d = container_of(ptr, struct data__file, fmt);
397
398         return get_pair_data(he, d);
399 }
400
401 static void hists__baseline_only(struct hists *hists)
402 {
403         struct rb_root *root;
404         struct rb_node *next;
405
406         if (sort__need_collapse)
407                 root = &hists->entries_collapsed;
408         else
409                 root = hists->entries_in;
410
411         next = rb_first(root);
412         while (next != NULL) {
413                 struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
414
415                 next = rb_next(&he->rb_node_in);
416                 if (!hist_entry__next_pair(he)) {
417                         rb_erase(&he->rb_node_in, root);
418                         hist_entry__free(he);
419                 }
420         }
421 }
422
423 static void hists__precompute(struct hists *hists)
424 {
425         struct rb_root *root;
426         struct rb_node *next;
427
428         if (sort__need_collapse)
429                 root = &hists->entries_collapsed;
430         else
431                 root = hists->entries_in;
432
433         next = rb_first(root);
434         while (next != NULL) {
435                 struct hist_entry *he, *pair;
436
437                 he   = rb_entry(next, struct hist_entry, rb_node_in);
438                 next = rb_next(&he->rb_node_in);
439
440                 pair = get_pair_data(he, &data__files[sort_compute]);
441                 if (!pair)
442                         continue;
443
444                 switch (compute) {
445                 case COMPUTE_DELTA:
446                         compute_delta(he, pair);
447                         break;
448                 case COMPUTE_RATIO:
449                         compute_ratio(he, pair);
450                         break;
451                 case COMPUTE_WEIGHTED_DIFF:
452                         compute_wdiff(he, pair);
453                         break;
454                 default:
455                         BUG_ON(1);
456                 }
457         }
458 }
459
460 static int64_t cmp_doubles(double l, double r)
461 {
462         if (l > r)
463                 return -1;
464         else if (l < r)
465                 return 1;
466         else
467                 return 0;
468 }
469
470 static int64_t
471 __hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
472                         int c)
473 {
474         switch (c) {
475         case COMPUTE_DELTA:
476         {
477                 double l = left->diff.period_ratio_delta;
478                 double r = right->diff.period_ratio_delta;
479
480                 return cmp_doubles(l, r);
481         }
482         case COMPUTE_RATIO:
483         {
484                 double l = left->diff.period_ratio;
485                 double r = right->diff.period_ratio;
486
487                 return cmp_doubles(l, r);
488         }
489         case COMPUTE_WEIGHTED_DIFF:
490         {
491                 s64 l = left->diff.wdiff;
492                 s64 r = right->diff.wdiff;
493
494                 return r - l;
495         }
496         default:
497                 BUG_ON(1);
498         }
499
500         return 0;
501 }
502
503 static int64_t
504 hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
505                         int c)
506 {
507         bool pairs_left  = hist_entry__has_pairs(left);
508         bool pairs_right = hist_entry__has_pairs(right);
509         struct hist_entry *p_right, *p_left;
510
511         if (!pairs_left && !pairs_right)
512                 return 0;
513
514         if (!pairs_left || !pairs_right)
515                 return pairs_left ? -1 : 1;
516
517         p_left  = get_pair_data(left,  &data__files[sort_compute]);
518         p_right = get_pair_data(right, &data__files[sort_compute]);
519
520         if (!p_left && !p_right)
521                 return 0;
522
523         if (!p_left || !p_right)
524                 return p_left ? -1 : 1;
525
526         /*
527          * We have 2 entries of same kind, let's
528          * make the data comparison.
529          */
530         return __hist_entry__cmp_compute(p_left, p_right, c);
531 }
532
533 static void insert_hist_entry_by_compute(struct rb_root *root,
534                                          struct hist_entry *he,
535                                          int c)
536 {
537         struct rb_node **p = &root->rb_node;
538         struct rb_node *parent = NULL;
539         struct hist_entry *iter;
540
541         while (*p != NULL) {
542                 parent = *p;
543                 iter = rb_entry(parent, struct hist_entry, rb_node);
544                 if (hist_entry__cmp_compute(he, iter, c) < 0)
545                         p = &(*p)->rb_left;
546                 else
547                         p = &(*p)->rb_right;
548         }
549
550         rb_link_node(&he->rb_node, parent, p);
551         rb_insert_color(&he->rb_node, root);
552 }
553
554 static void hists__compute_resort(struct hists *hists)
555 {
556         struct rb_root *root;
557         struct rb_node *next;
558
559         if (sort__need_collapse)
560                 root = &hists->entries_collapsed;
561         else
562                 root = hists->entries_in;
563
564         hists->entries = RB_ROOT;
565         next = rb_first(root);
566
567         hists->nr_entries = 0;
568         hists->stats.total_period = 0;
569         hists__reset_col_len(hists);
570
571         while (next != NULL) {
572                 struct hist_entry *he;
573
574                 he = rb_entry(next, struct hist_entry, rb_node_in);
575                 next = rb_next(&he->rb_node_in);
576
577                 insert_hist_entry_by_compute(&hists->entries, he, compute);
578                 hists__inc_nr_entries(hists, he);
579         }
580 }
581
582 static void hists__process(struct hists *hists)
583 {
584         if (show_baseline_only)
585                 hists__baseline_only(hists);
586
587         if (sort_compute) {
588                 hists__precompute(hists);
589                 hists__compute_resort(hists);
590         } else {
591                 hists__output_resort(hists);
592         }
593
594         hists__fprintf(hists, true, 0, 0, 0, stdout);
595 }
596
597 static void data__fprintf(void)
598 {
599         struct data__file *d;
600         int i;
601
602         fprintf(stdout, "# Data files:\n");
603
604         data__for_each_file(i, d)
605                 fprintf(stdout, "#  [%d] %s %s\n",
606                         d->idx, d->file.path,
607                         !d->idx ? "(Baseline)" : "");
608
609         fprintf(stdout, "#\n");
610 }
611
612 static void data_process(void)
613 {
614         struct perf_evlist *evlist_base = data__files[0].session->evlist;
615         struct perf_evsel *evsel_base;
616         bool first = true;
617
618         evlist__for_each(evlist_base, evsel_base) {
619                 struct data__file *d;
620                 int i;
621
622                 data__for_each_file_new(i, d) {
623                         struct perf_evlist *evlist = d->session->evlist;
624                         struct perf_evsel *evsel;
625
626                         evsel = evsel_match(evsel_base, evlist);
627                         if (!evsel)
628                                 continue;
629
630                         d->hists = &evsel->hists;
631
632                         hists__match(&evsel_base->hists, &evsel->hists);
633
634                         if (!show_baseline_only)
635                                 hists__link(&evsel_base->hists,
636                                             &evsel->hists);
637                 }
638
639                 fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
640                         perf_evsel__name(evsel_base));
641
642                 first = false;
643
644                 if (verbose || data__files_cnt > 2)
645                         data__fprintf();
646
647                 hists__process(&evsel_base->hists);
648         }
649 }
650
651 static void data__free(struct data__file *d)
652 {
653         int col;
654
655         for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
656                 struct diff_hpp_fmt *fmt = &d->fmt[col];
657
658                 zfree(&fmt->header);
659         }
660 }
661
662 static int __cmd_diff(void)
663 {
664         struct data__file *d;
665         int ret = -EINVAL, i;
666
667         data__for_each_file(i, d) {
668                 d->session = perf_session__new(&d->file, false, &tool);
669                 if (!d->session) {
670                         pr_err("Failed to open %s\n", d->file.path);
671                         ret = -ENOMEM;
672                         goto out_delete;
673                 }
674
675                 ret = perf_session__process_events(d->session, &tool);
676                 if (ret) {
677                         pr_err("Failed to process %s\n", d->file.path);
678                         goto out_delete;
679                 }
680
681                 perf_evlist__collapse_resort(d->session->evlist);
682         }
683
684         data_process();
685
686  out_delete:
687         data__for_each_file(i, d) {
688                 if (d->session)
689                         perf_session__delete(d->session);
690
691                 data__free(d);
692         }
693
694         free(data__files);
695         return ret;
696 }
697
698 static const char * const diff_usage[] = {
699         "perf diff [<options>] [old_file] [new_file]",
700         NULL,
701 };
702
703 static const struct option options[] = {
704         OPT_INCR('v', "verbose", &verbose,
705                     "be more verbose (show symbol address, etc)"),
706         OPT_BOOLEAN('b', "baseline-only", &show_baseline_only,
707                     "Show only items with match in baseline"),
708         OPT_CALLBACK('c', "compute", &compute,
709                      "delta,ratio,wdiff:w1,w2 (default delta)",
710                      "Entries differential computation selection",
711                      setup_compute),
712         OPT_BOOLEAN('p', "period", &show_period,
713                     "Show period values."),
714         OPT_BOOLEAN('F', "formula", &show_formula,
715                     "Show formula."),
716         OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
717                     "dump raw trace in ASCII"),
718         OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
719         OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
720                     "load module symbols - WARNING: use only with -k and LIVE kernel"),
721         OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
722                    "only consider symbols in these dsos"),
723         OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
724                    "only consider symbols in these comms"),
725         OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
726                    "only consider these symbols"),
727         OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
728                    "sort by key(s): pid, comm, dso, symbol, parent"),
729         OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
730                    "separator for columns, no spaces will be added between "
731                    "columns '.' is reserved."),
732         OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
733                     "Look for files with symbols relative to this directory"),
734         OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
735         OPT_END()
736 };
737
738 static double baseline_percent(struct hist_entry *he)
739 {
740         struct hists *hists = he->hists;
741         return 100.0 * he->stat.period / hists->stats.total_period;
742 }
743
744 static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
745                                struct perf_hpp *hpp, struct hist_entry *he)
746 {
747         struct diff_hpp_fmt *dfmt =
748                 container_of(fmt, struct diff_hpp_fmt, fmt);
749         double percent = baseline_percent(he);
750         char pfmt[20] = " ";
751
752         if (!he->dummy) {
753                 scnprintf(pfmt, 20, "%%%d.2f%%%%", dfmt->header_width - 1);
754                 return percent_color_snprintf(hpp->buf, hpp->size,
755                                               pfmt, percent);
756         } else
757                 return scnprintf(hpp->buf, hpp->size, "%*s",
758                                  dfmt->header_width, pfmt);
759 }
760
761 static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size)
762 {
763         double percent = baseline_percent(he);
764         const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
765         int ret = 0;
766
767         if (!he->dummy)
768                 ret = scnprintf(buf, size, fmt, percent);
769
770         return ret;
771 }
772
773 static int __hpp__color_compare(struct perf_hpp_fmt *fmt,
774                                 struct perf_hpp *hpp, struct hist_entry *he,
775                                 int comparison_method)
776 {
777         struct diff_hpp_fmt *dfmt =
778                 container_of(fmt, struct diff_hpp_fmt, fmt);
779         struct hist_entry *pair = get_pair_fmt(he, dfmt);
780         double diff;
781         s64 wdiff;
782         char pfmt[20] = " ";
783
784         if (!pair)
785                 goto dummy_print;
786
787         switch (comparison_method) {
788         case COMPUTE_DELTA:
789                 if (pair->diff.computed)
790                         diff = pair->diff.period_ratio_delta;
791                 else
792                         diff = compute_delta(he, pair);
793
794                 if (fabs(diff) < 0.01)
795                         goto dummy_print;
796                 scnprintf(pfmt, 20, "%%%+d.2f%%%%", dfmt->header_width - 1);
797                 return percent_color_snprintf(hpp->buf, hpp->size,
798                                         pfmt, diff);
799         case COMPUTE_RATIO:
800                 if (he->dummy)
801                         goto dummy_print;
802                 if (pair->diff.computed)
803                         diff = pair->diff.period_ratio;
804                 else
805                         diff = compute_ratio(he, pair);
806
807                 scnprintf(pfmt, 20, "%%%d.6f", dfmt->header_width);
808                 return value_color_snprintf(hpp->buf, hpp->size,
809                                         pfmt, diff);
810         case COMPUTE_WEIGHTED_DIFF:
811                 if (he->dummy)
812                         goto dummy_print;
813                 if (pair->diff.computed)
814                         wdiff = pair->diff.wdiff;
815                 else
816                         wdiff = compute_wdiff(he, pair);
817
818                 scnprintf(pfmt, 20, "%%14ld", dfmt->header_width);
819                 return color_snprintf(hpp->buf, hpp->size,
820                                 get_percent_color(wdiff),
821                                 pfmt, wdiff);
822         default:
823                 BUG_ON(1);
824         }
825 dummy_print:
826         return scnprintf(hpp->buf, hpp->size, "%*s",
827                         dfmt->header_width, pfmt);
828 }
829
830 static int hpp__color_delta(struct perf_hpp_fmt *fmt,
831                         struct perf_hpp *hpp, struct hist_entry *he)
832 {
833         return __hpp__color_compare(fmt, hpp, he, COMPUTE_DELTA);
834 }
835
836 static int hpp__color_ratio(struct perf_hpp_fmt *fmt,
837                         struct perf_hpp *hpp, struct hist_entry *he)
838 {
839         return __hpp__color_compare(fmt, hpp, he, COMPUTE_RATIO);
840 }
841
842 static int hpp__color_wdiff(struct perf_hpp_fmt *fmt,
843                         struct perf_hpp *hpp, struct hist_entry *he)
844 {
845         return __hpp__color_compare(fmt, hpp, he, COMPUTE_WEIGHTED_DIFF);
846 }
847
848 static void
849 hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
850 {
851         switch (idx) {
852         case PERF_HPP_DIFF__PERIOD_BASELINE:
853                 scnprintf(buf, size, "%" PRIu64, he->stat.period);
854                 break;
855
856         default:
857                 break;
858         }
859 }
860
861 static void
862 hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,
863                 int idx, char *buf, size_t size)
864 {
865         double diff;
866         double ratio;
867         s64 wdiff;
868
869         switch (idx) {
870         case PERF_HPP_DIFF__DELTA:
871                 if (pair->diff.computed)
872                         diff = pair->diff.period_ratio_delta;
873                 else
874                         diff = compute_delta(he, pair);
875
876                 if (fabs(diff) >= 0.01)
877                         scnprintf(buf, size, "%+4.2F%%", diff);
878                 break;
879
880         case PERF_HPP_DIFF__RATIO:
881                 /* No point for ratio number if we are dummy.. */
882                 if (he->dummy)
883                         break;
884
885                 if (pair->diff.computed)
886                         ratio = pair->diff.period_ratio;
887                 else
888                         ratio = compute_ratio(he, pair);
889
890                 if (ratio > 0.0)
891                         scnprintf(buf, size, "%14.6F", ratio);
892                 break;
893
894         case PERF_HPP_DIFF__WEIGHTED_DIFF:
895                 /* No point for wdiff number if we are dummy.. */
896                 if (he->dummy)
897                         break;
898
899                 if (pair->diff.computed)
900                         wdiff = pair->diff.wdiff;
901                 else
902                         wdiff = compute_wdiff(he, pair);
903
904                 if (wdiff != 0)
905                         scnprintf(buf, size, "%14ld", wdiff);
906                 break;
907
908         case PERF_HPP_DIFF__FORMULA:
909                 formula_fprintf(he, pair, buf, size);
910                 break;
911
912         case PERF_HPP_DIFF__PERIOD:
913                 scnprintf(buf, size, "%" PRIu64, pair->stat.period);
914                 break;
915
916         default:
917                 BUG_ON(1);
918         };
919 }
920
921 static void
922 __hpp__entry_global(struct hist_entry *he, struct diff_hpp_fmt *dfmt,
923                     char *buf, size_t size)
924 {
925         struct hist_entry *pair = get_pair_fmt(he, dfmt);
926         int idx = dfmt->idx;
927
928         /* baseline is special */
929         if (idx == PERF_HPP_DIFF__BASELINE)
930                 hpp__entry_baseline(he, buf, size);
931         else {
932                 if (pair)
933                         hpp__entry_pair(he, pair, idx, buf, size);
934                 else
935                         hpp__entry_unpair(he, idx, buf, size);
936         }
937 }
938
939 static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
940                              struct hist_entry *he)
941 {
942         struct diff_hpp_fmt *dfmt =
943                 container_of(_fmt, struct diff_hpp_fmt, fmt);
944         char buf[MAX_COL_WIDTH] = " ";
945
946         __hpp__entry_global(he, dfmt, buf, MAX_COL_WIDTH);
947
948         if (symbol_conf.field_sep)
949                 return scnprintf(hpp->buf, hpp->size, "%s", buf);
950         else
951                 return scnprintf(hpp->buf, hpp->size, "%*s",
952                                  dfmt->header_width, buf);
953 }
954
955 static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
956                        struct perf_evsel *evsel __maybe_unused)
957 {
958         struct diff_hpp_fmt *dfmt =
959                 container_of(fmt, struct diff_hpp_fmt, fmt);
960
961         BUG_ON(!dfmt->header);
962         return scnprintf(hpp->buf, hpp->size, dfmt->header);
963 }
964
965 static int hpp__width(struct perf_hpp_fmt *fmt,
966                       struct perf_hpp *hpp __maybe_unused,
967                       struct perf_evsel *evsel __maybe_unused)
968 {
969         struct diff_hpp_fmt *dfmt =
970                 container_of(fmt, struct diff_hpp_fmt, fmt);
971
972         BUG_ON(dfmt->header_width <= 0);
973         return dfmt->header_width;
974 }
975
976 static void init_header(struct data__file *d, struct diff_hpp_fmt *dfmt)
977 {
978 #define MAX_HEADER_NAME 100
979         char buf_indent[MAX_HEADER_NAME];
980         char buf[MAX_HEADER_NAME];
981         const char *header = NULL;
982         int width = 0;
983
984         BUG_ON(dfmt->idx >= PERF_HPP_DIFF__MAX_INDEX);
985         header = columns[dfmt->idx].name;
986         width  = columns[dfmt->idx].width;
987
988         /* Only our defined HPP fmts should appear here. */
989         BUG_ON(!header);
990
991         if (data__files_cnt > 2)
992                 scnprintf(buf, MAX_HEADER_NAME, "%s/%d", header, d->idx);
993
994 #define NAME (data__files_cnt > 2 ? buf : header)
995         dfmt->header_width = width;
996         width = (int) strlen(NAME);
997         if (dfmt->header_width < width)
998                 dfmt->header_width = width;
999
1000         scnprintf(buf_indent, MAX_HEADER_NAME, "%*s",
1001                   dfmt->header_width, NAME);
1002
1003         dfmt->header = strdup(buf_indent);
1004 #undef MAX_HEADER_NAME
1005 #undef NAME
1006 }
1007
1008 static void data__hpp_register(struct data__file *d, int idx)
1009 {
1010         struct diff_hpp_fmt *dfmt = &d->fmt[idx];
1011         struct perf_hpp_fmt *fmt = &dfmt->fmt;
1012
1013         dfmt->idx = idx;
1014
1015         fmt->header = hpp__header;
1016         fmt->width  = hpp__width;
1017         fmt->entry  = hpp__entry_global;
1018
1019         /* TODO more colors */
1020         switch (idx) {
1021         case PERF_HPP_DIFF__BASELINE:
1022                 fmt->color = hpp__color_baseline;
1023                 break;
1024         case PERF_HPP_DIFF__DELTA:
1025                 fmt->color = hpp__color_delta;
1026                 break;
1027         case PERF_HPP_DIFF__RATIO:
1028                 fmt->color = hpp__color_ratio;
1029                 break;
1030         case PERF_HPP_DIFF__WEIGHTED_DIFF:
1031                 fmt->color = hpp__color_wdiff;
1032                 break;
1033         default:
1034                 break;
1035         }
1036
1037         init_header(d, dfmt);
1038         perf_hpp__column_register(fmt);
1039 }
1040
1041 static void ui_init(void)
1042 {
1043         struct data__file *d;
1044         int i;
1045
1046         data__for_each_file(i, d) {
1047
1048                 /*
1049                  * Baseline or compute realted columns:
1050                  *
1051                  *   PERF_HPP_DIFF__BASELINE
1052                  *   PERF_HPP_DIFF__DELTA
1053                  *   PERF_HPP_DIFF__RATIO
1054                  *   PERF_HPP_DIFF__WEIGHTED_DIFF
1055                  */
1056                 data__hpp_register(d, i ? compute_2_hpp[compute] :
1057                                           PERF_HPP_DIFF__BASELINE);
1058
1059                 /*
1060                  * And the rest:
1061                  *
1062                  * PERF_HPP_DIFF__FORMULA
1063                  * PERF_HPP_DIFF__PERIOD
1064                  * PERF_HPP_DIFF__PERIOD_BASELINE
1065                  */
1066                 if (show_formula && i)
1067                         data__hpp_register(d, PERF_HPP_DIFF__FORMULA);
1068
1069                 if (show_period)
1070                         data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD :
1071                                                   PERF_HPP_DIFF__PERIOD_BASELINE);
1072         }
1073 }
1074
1075 static int data_init(int argc, const char **argv)
1076 {
1077         struct data__file *d;
1078         static const char *defaults[] = {
1079                 "perf.data.old",
1080                 "perf.data",
1081         };
1082         bool use_default = true;
1083         int i;
1084
1085         data__files_cnt = 2;
1086
1087         if (argc) {
1088                 if (argc == 1)
1089                         defaults[1] = argv[0];
1090                 else {
1091                         data__files_cnt = argc;
1092                         use_default = false;
1093                 }
1094         } else if (perf_guest) {
1095                 defaults[0] = "perf.data.host";
1096                 defaults[1] = "perf.data.guest";
1097         }
1098
1099         if (sort_compute >= (unsigned int) data__files_cnt) {
1100                 pr_err("Order option out of limit.\n");
1101                 return -EINVAL;
1102         }
1103
1104         data__files = zalloc(sizeof(*data__files) * data__files_cnt);
1105         if (!data__files)
1106                 return -ENOMEM;
1107
1108         data__for_each_file(i, d) {
1109                 struct perf_data_file *file = &d->file;
1110
1111                 file->path  = use_default ? defaults[i] : argv[i];
1112                 file->mode  = PERF_DATA_MODE_READ,
1113                 file->force = force,
1114
1115                 d->idx  = i;
1116         }
1117
1118         return 0;
1119 }
1120
1121 int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
1122 {
1123         sort_order = diff__default_sort_order;
1124         argc = parse_options(argc, argv, options, diff_usage, 0);
1125
1126         if (symbol__init() < 0)
1127                 return -1;
1128
1129         if (data_init(argc, argv) < 0)
1130                 return -1;
1131
1132         ui_init();
1133
1134         if (setup_sorting() < 0)
1135                 usage_with_options(diff_usage, options);
1136
1137         setup_pager();
1138
1139         sort__setup_elide(NULL);
1140
1141         return __cmd_diff();
1142 }