linux/tools/perf/builtin-diff.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * builtin-diff.c
   4 *
   5 * Builtin diff command: Analyze two perf.data input files, look up and read
   6 * DSOs and symbol information, sort them and produce a diff.
   7 */
   8#include "builtin.h"
   9
  10#include "util/debug.h"
  11#include "util/event.h"
  12#include "util/hist.h"
  13#include "util/evsel.h"
  14#include "util/evlist.h"
  15#include "util/session.h"
  16#include "util/tool.h"
  17#include "util/sort.h"
  18#include "util/symbol.h"
  19#include "util/data.h"
  20#include "util/config.h"
  21#include "util/time-utils.h"
  22#include "util/annotate.h"
  23#include "util/map.h"
  24#include <linux/zalloc.h>
  25
  26#include <errno.h>
  27#include <inttypes.h>
  28#include <stdlib.h>
  29#include <math.h>
  30
  31struct perf_diff {
  32        struct perf_tool                 tool;
  33        const char                      *time_str;
  34        struct perf_time_interval       *ptime_range;
  35        int                              range_size;
  36        int                              range_num;
  37        bool                             has_br_stack;
  38};
  39
  40/* Diff command specific HPP columns. */
  41enum {
  42        PERF_HPP_DIFF__BASELINE,
  43        PERF_HPP_DIFF__PERIOD,
  44        PERF_HPP_DIFF__PERIOD_BASELINE,
  45        PERF_HPP_DIFF__DELTA,
  46        PERF_HPP_DIFF__RATIO,
  47        PERF_HPP_DIFF__WEIGHTED_DIFF,
  48        PERF_HPP_DIFF__FORMULA,
  49        PERF_HPP_DIFF__DELTA_ABS,
  50        PERF_HPP_DIFF__CYCLES,
  51
  52        PERF_HPP_DIFF__MAX_INDEX
  53};
  54
  55struct diff_hpp_fmt {
  56        struct perf_hpp_fmt      fmt;
  57        int                      idx;
  58        char                    *header;
  59        int                      header_width;
  60};
  61
  62struct data__file {
  63        struct perf_session     *session;
  64        struct perf_data         data;
  65        int                      idx;
  66        struct hists            *hists;
  67        struct diff_hpp_fmt      fmt[PERF_HPP_DIFF__MAX_INDEX];
  68};
  69
  70static struct data__file *data__files;
  71static int data__files_cnt;
  72
  73#define data__for_each_file_start(i, d, s)      \
  74        for (i = s, d = &data__files[s];        \
  75             i < data__files_cnt;               \
  76             i++, d = &data__files[i])
  77
  78#define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
  79#define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
  80
  81static bool force;
  82static bool show_period;
  83static bool show_formula;
  84static bool show_baseline_only;
  85static unsigned int sort_compute = 1;
  86
  87static s64 compute_wdiff_w1;
  88static s64 compute_wdiff_w2;
  89
  90static const char               *cpu_list;
  91static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
  92
  93static struct addr_location dummy_al;
  94
  95enum {
  96        COMPUTE_DELTA,
  97        COMPUTE_RATIO,
  98        COMPUTE_WEIGHTED_DIFF,
  99        COMPUTE_DELTA_ABS,
 100        COMPUTE_CYCLES,
 101        COMPUTE_MAX,
 102};
 103
 104const char *compute_names[COMPUTE_MAX] = {
 105        [COMPUTE_DELTA] = "delta",
 106        [COMPUTE_DELTA_ABS] = "delta-abs",
 107        [COMPUTE_RATIO] = "ratio",
 108        [COMPUTE_WEIGHTED_DIFF] = "wdiff",
 109        [COMPUTE_CYCLES] = "cycles",
 110};
 111
 112static int compute = COMPUTE_DELTA_ABS;
 113
 114static int compute_2_hpp[COMPUTE_MAX] = {
 115        [COMPUTE_DELTA]         = PERF_HPP_DIFF__DELTA,
 116        [COMPUTE_DELTA_ABS]     = PERF_HPP_DIFF__DELTA_ABS,
 117        [COMPUTE_RATIO]         = PERF_HPP_DIFF__RATIO,
 118        [COMPUTE_WEIGHTED_DIFF] = PERF_HPP_DIFF__WEIGHTED_DIFF,
 119        [COMPUTE_CYCLES]        = PERF_HPP_DIFF__CYCLES,
 120};
 121
 122#define MAX_COL_WIDTH 70
 123
 124static struct header_column {
 125        const char *name;
 126        int width;
 127} columns[PERF_HPP_DIFF__MAX_INDEX] = {
 128        [PERF_HPP_DIFF__BASELINE] = {
 129                .name  = "Baseline",
 130        },
 131        [PERF_HPP_DIFF__PERIOD] = {
 132                .name  = "Period",
 133                .width = 14,
 134        },
 135        [PERF_HPP_DIFF__PERIOD_BASELINE] = {
 136                .name  = "Base period",
 137                .width = 14,
 138        },
 139        [PERF_HPP_DIFF__DELTA] = {
 140                .name  = "Delta",
 141                .width = 7,
 142        },
 143        [PERF_HPP_DIFF__DELTA_ABS] = {
 144                .name  = "Delta Abs",
 145                .width = 7,
 146        },
 147        [PERF_HPP_DIFF__RATIO] = {
 148                .name  = "Ratio",
 149                .width = 14,
 150        },
 151        [PERF_HPP_DIFF__WEIGHTED_DIFF] = {
 152                .name  = "Weighted diff",
 153                .width = 14,
 154        },
 155        [PERF_HPP_DIFF__FORMULA] = {
 156                .name  = "Formula",
 157                .width = MAX_COL_WIDTH,
 158        },
 159        [PERF_HPP_DIFF__CYCLES] = {
 160                .name  = "[Program Block Range] Cycles Diff",
 161                .width = 70,
 162        }
 163};
 164
 165static int setup_compute_opt_wdiff(char *opt)
 166{
 167        char *w1_str = opt;
 168        char *w2_str;
 169
 170        int ret = -EINVAL;
 171
 172        if (!opt)
 173                goto out;
 174
 175        w2_str = strchr(opt, ',');
 176        if (!w2_str)
 177                goto out;
 178
 179        *w2_str++ = 0x0;
 180        if (!*w2_str)
 181                goto out;
 182
 183        compute_wdiff_w1 = strtol(w1_str, NULL, 10);
 184        compute_wdiff_w2 = strtol(w2_str, NULL, 10);
 185
 186        if (!compute_wdiff_w1 || !compute_wdiff_w2)
 187                goto out;
 188
 189        pr_debug("compute wdiff w1(%" PRId64 ") w2(%" PRId64 ")\n",
 190                  compute_wdiff_w1, compute_wdiff_w2);
 191
 192        ret = 0;
 193
 194 out:
 195        if (ret)
 196                pr_err("Failed: wrong weight data, use 'wdiff:w1,w2'\n");
 197
 198        return ret;
 199}
 200
 201static int setup_compute_opt(char *opt)
 202{
 203        if (compute == COMPUTE_WEIGHTED_DIFF)
 204                return setup_compute_opt_wdiff(opt);
 205
 206        if (opt) {
 207                pr_err("Failed: extra option specified '%s'", opt);
 208                return -EINVAL;
 209        }
 210
 211        return 0;
 212}
 213
 214static int setup_compute(const struct option *opt, const char *str,
 215                         int unset __maybe_unused)
 216{
 217        int *cp = (int *) opt->value;
 218        char *cstr = (char *) str;
 219        char buf[50];
 220        unsigned i;
 221        char *option;
 222
 223        if (!str) {
 224                *cp = COMPUTE_DELTA;
 225                return 0;
 226        }
 227
 228        option = strchr(str, ':');
 229        if (option) {
 230                unsigned len = option++ - str;
 231
 232                /*
 233                 * The str data are not writeable, so we need
 234                 * to use another buffer.
 235                 */
 236
 237                /* No option value is longer. */
 238                if (len >= sizeof(buf))
 239                        return -EINVAL;
 240
 241                strncpy(buf, str, len);
 242                buf[len] = 0x0;
 243                cstr = buf;
 244        }
 245
 246        for (i = 0; i < COMPUTE_MAX; i++)
 247                if (!strcmp(cstr, compute_names[i])) {
 248                        *cp = i;
 249                        return setup_compute_opt(option);
 250                }
 251
 252        pr_err("Failed: '%s' is not computation method "
 253               "(use 'delta','ratio' or 'wdiff')\n", str);
 254        return -EINVAL;
 255}
 256
 257static double period_percent(struct hist_entry *he, u64 period)
 258{
 259        u64 total = hists__total_period(he->hists);
 260
 261        return (period * 100.0) / total;
 262}
 263
 264static double compute_delta(struct hist_entry *he, struct hist_entry *pair)
 265{
 266        double old_percent = period_percent(he, he->stat.period);
 267        double new_percent = period_percent(pair, pair->stat.period);
 268
 269        pair->diff.period_ratio_delta = new_percent - old_percent;
 270        pair->diff.computed = true;
 271        return pair->diff.period_ratio_delta;
 272}
 273
 274static double compute_ratio(struct hist_entry *he, struct hist_entry *pair)
 275{
 276        double old_period = he->stat.period ?: 1;
 277        double new_period = pair->stat.period;
 278
 279        pair->diff.computed = true;
 280        pair->diff.period_ratio = new_period / old_period;
 281        return pair->diff.period_ratio;
 282}
 283
 284static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
 285{
 286        u64 old_period = he->stat.period;
 287        u64 new_period = pair->stat.period;
 288
 289        pair->diff.computed = true;
 290        pair->diff.wdiff = new_period * compute_wdiff_w2 -
 291                           old_period * compute_wdiff_w1;
 292
 293        return pair->diff.wdiff;
 294}
 295
 296static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
 297                         char *buf, size_t size)
 298{
 299        u64 he_total = he->hists->stats.total_period;
 300        u64 pair_total = pair->hists->stats.total_period;
 301
 302        if (symbol_conf.filter_relative) {
 303                he_total = he->hists->stats.total_non_filtered_period;
 304                pair_total = pair->hists->stats.total_non_filtered_period;
 305        }
 306        return scnprintf(buf, size,
 307                         "(%" PRIu64 " * 100 / %" PRIu64 ") - "
 308                         "(%" PRIu64 " * 100 / %" PRIu64 ")",
 309                         pair->stat.period, pair_total,
 310                         he->stat.period, he_total);
 311}
 312
 313static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
 314                         char *buf, size_t size)
 315{
 316        double old_period = he->stat.period;
 317        double new_period = pair->stat.period;
 318
 319        return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
 320}
 321
 322static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
 323                         char *buf, size_t size)
 324{
 325        u64 old_period = he->stat.period;
 326        u64 new_period = pair->stat.period;
 327
 328        return scnprintf(buf, size,
 329                  "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
 330                  new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
 331}
 332
 333static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
 334                           char *buf, size_t size)
 335{
 336        switch (compute) {
 337        case COMPUTE_DELTA:
 338        case COMPUTE_DELTA_ABS:
 339                return formula_delta(he, pair, buf, size);
 340        case COMPUTE_RATIO:
 341                return formula_ratio(he, pair, buf, size);
 342        case COMPUTE_WEIGHTED_DIFF:
 343                return formula_wdiff(he, pair, buf, size);
 344        default:
 345                BUG_ON(1);
 346        }
 347
 348        return -1;
 349}
 350
 351static void *block_hist_zalloc(size_t size)
 352{
 353        struct block_hist *bh;
 354
 355        bh = zalloc(size + sizeof(*bh));
 356        if (!bh)
 357                return NULL;
 358
 359        return &bh->he;
 360}
 361
 362static void block_hist_free(void *he)
 363{
 364        struct block_hist *bh;
 365
 366        bh = container_of(he, struct block_hist, he);
 367        hists__delete_entries(&bh->block_hists);
 368        free(bh);
 369}
 370
 371struct hist_entry_ops block_hist_ops = {
 372        .new    = block_hist_zalloc,
 373        .free   = block_hist_free,
 374};
 375
 376static int diff__process_sample_event(struct perf_tool *tool,
 377                                      union perf_event *event,
 378                                      struct perf_sample *sample,
 379                                      struct perf_evsel *evsel,
 380                                      struct machine *machine)
 381{
 382        struct perf_diff *pdiff = container_of(tool, struct perf_diff, tool);
 383        struct addr_location al;
 384        struct hists *hists = evsel__hists(evsel);
 385        int ret = -1;
 386
 387        if (perf_time__ranges_skip_sample(pdiff->ptime_range, pdiff->range_num,
 388                                          sample->time)) {
 389                return 0;
 390        }
 391
 392        if (machine__resolve(machine, &al, sample) < 0) {
 393                pr_warning("problem processing %d event, skipping it.\n",
 394                           event->header.type);
 395                return -1;
 396        }
 397
 398        if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) {
 399                ret = 0;
 400                goto out_put;
 401        }
 402
 403        if (compute != COMPUTE_CYCLES) {
 404                if (!hists__add_entry(hists, &al, NULL, NULL, NULL, sample,
 405                                      true)) {
 406                        pr_warning("problem incrementing symbol period, "
 407                                   "skipping event\n");
 408                        goto out_put;
 409                }
 410        } else {
 411                if (!hists__add_entry_ops(hists, &block_hist_ops, &al, NULL,
 412                                          NULL, NULL, sample, true)) {
 413                        pr_warning("problem incrementing symbol period, "
 414                                   "skipping event\n");
 415                        goto out_put;
 416                }
 417
 418                hist__account_cycles(sample->branch_stack, &al, sample, false);
 419        }
 420
 421        /*
 422         * The total_period is updated here before going to the output
 423         * tree since normally only the baseline hists will call
 424         * hists__output_resort() and precompute needs the total
 425         * period in order to sort entries by percentage delta.
 426         */
 427        hists->stats.total_period += sample->period;
 428        if (!al.filtered)
 429                hists->stats.total_non_filtered_period += sample->period;
 430        ret = 0;
 431out_put:
 432        addr_location__put(&al);
 433        return ret;
 434}
 435
 436static struct perf_diff pdiff = {
 437        .tool = {
 438                .sample = diff__process_sample_event,
 439                .mmap   = perf_event__process_mmap,
 440                .mmap2  = perf_event__process_mmap2,
 441                .comm   = perf_event__process_comm,
 442                .exit   = perf_event__process_exit,
 443                .fork   = perf_event__process_fork,
 444                .lost   = perf_event__process_lost,
 445                .namespaces = perf_event__process_namespaces,
 446                .ordered_events = true,
 447                .ordering_requires_timestamps = true,
 448        },
 449};
 450
 451static struct perf_evsel *evsel_match(struct perf_evsel *evsel,
 452                                      struct perf_evlist *evlist)
 453{
 454        struct perf_evsel *e;
 455
 456        evlist__for_each_entry(evlist, e) {
 457                if (perf_evsel__match2(evsel, e))
 458                        return e;
 459        }
 460
 461        return NULL;
 462}
 463
 464static void perf_evlist__collapse_resort(struct perf_evlist *evlist)
 465{
 466        struct perf_evsel *evsel;
 467
 468        evlist__for_each_entry(evlist, evsel) {
 469                struct hists *hists = evsel__hists(evsel);
 470
 471                hists__collapse_resort(hists, NULL);
 472        }
 473}
 474
 475static struct data__file *fmt_to_data_file(struct perf_hpp_fmt *fmt)
 476{
 477        struct diff_hpp_fmt *dfmt = container_of(fmt, struct diff_hpp_fmt, fmt);
 478        void *ptr = dfmt - dfmt->idx;
 479        struct data__file *d = container_of(ptr, struct data__file, fmt);
 480
 481        return d;
 482}
 483
 484static struct hist_entry*
 485get_pair_data(struct hist_entry *he, struct data__file *d)
 486{
 487        if (hist_entry__has_pairs(he)) {
 488                struct hist_entry *pair;
 489
 490                list_for_each_entry(pair, &he->pairs.head, pairs.node)
 491                        if (pair->hists == d->hists)
 492                                return pair;
 493        }
 494
 495        return NULL;
 496}
 497
 498static struct hist_entry*
 499get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt)
 500{
 501        struct data__file *d = fmt_to_data_file(&dfmt->fmt);
 502
 503        return get_pair_data(he, d);
 504}
 505
 506static void hists__baseline_only(struct hists *hists)
 507{
 508        struct rb_root_cached *root;
 509        struct rb_node *next;
 510
 511        if (hists__has(hists, need_collapse))
 512                root = &hists->entries_collapsed;
 513        else
 514                root = hists->entries_in;
 515
 516        next = rb_first_cached(root);
 517        while (next != NULL) {
 518                struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
 519
 520                next = rb_next(&he->rb_node_in);
 521                if (!hist_entry__next_pair(he)) {
 522                        rb_erase_cached(&he->rb_node_in, root);
 523                        hist_entry__delete(he);
 524                }
 525        }
 526}
 527
 528static int64_t block_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
 529                         struct hist_entry *left, struct hist_entry *right)
 530{
 531        struct block_info *bi_l = left->block_info;
 532        struct block_info *bi_r = right->block_info;
 533        int cmp;
 534
 535        if (!bi_l->sym || !bi_r->sym) {
 536                if (!bi_l->sym && !bi_r->sym)
 537                        return 0;
 538                else if (!bi_l->sym)
 539                        return -1;
 540                else
 541                        return 1;
 542        }
 543
 544        if (bi_l->sym == bi_r->sym) {
 545                if (bi_l->start == bi_r->start) {
 546                        if (bi_l->end == bi_r->end)
 547                                return 0;
 548                        else
 549                                return (int64_t)(bi_r->end - bi_l->end);
 550                } else
 551                        return (int64_t)(bi_r->start - bi_l->start);
 552        } else {
 553                cmp = strcmp(bi_l->sym->name, bi_r->sym->name);
 554                return cmp;
 555        }
 556
 557        if (bi_l->sym->start != bi_r->sym->start)
 558                return (int64_t)(bi_r->sym->start - bi_l->sym->start);
 559
 560        return (int64_t)(bi_r->sym->end - bi_l->sym->end);
 561}
 562
 563static int64_t block_cycles_diff_cmp(struct hist_entry *left,
 564                                     struct hist_entry *right)
 565{
 566        bool pairs_left  = hist_entry__has_pairs(left);
 567        bool pairs_right = hist_entry__has_pairs(right);
 568        s64 l, r;
 569
 570        if (!pairs_left && !pairs_right)
 571                return 0;
 572
 573        l = labs(left->diff.cycles);
 574        r = labs(right->diff.cycles);
 575        return r - l;
 576}
 577
 578static int64_t block_sort(struct perf_hpp_fmt *fmt __maybe_unused,
 579                          struct hist_entry *left, struct hist_entry *right)
 580{
 581        return block_cycles_diff_cmp(right, left);
 582}
 583
 584static void init_block_hist(struct block_hist *bh)
 585{
 586        __hists__init(&bh->block_hists, &bh->block_list);
 587        perf_hpp_list__init(&bh->block_list);
 588
 589        INIT_LIST_HEAD(&bh->block_fmt.list);
 590        INIT_LIST_HEAD(&bh->block_fmt.sort_list);
 591        bh->block_fmt.cmp = block_cmp;
 592        bh->block_fmt.sort = block_sort;
 593        perf_hpp_list__register_sort_field(&bh->block_list,
 594                                           &bh->block_fmt);
 595        bh->valid = true;
 596}
 597
 598static void init_block_info(struct block_info *bi, struct symbol *sym,
 599                            struct cyc_hist *ch, int offset)
 600{
 601        bi->sym = sym;
 602        bi->start = ch->start;
 603        bi->end = offset;
 604        bi->cycles = ch->cycles;
 605        bi->cycles_aggr = ch->cycles_aggr;
 606        bi->num = ch->num;
 607        bi->num_aggr = ch->num_aggr;
 608}
 609
 610static int process_block_per_sym(struct hist_entry *he)
 611{
 612        struct annotation *notes;
 613        struct cyc_hist *ch;
 614        struct block_hist *bh;
 615
 616        if (!he->ms.map || !he->ms.sym)
 617                return 0;
 618
 619        notes = symbol__annotation(he->ms.sym);
 620        if (!notes || !notes->src || !notes->src->cycles_hist)
 621                return 0;
 622
 623        bh = container_of(he, struct block_hist, he);
 624        init_block_hist(bh);
 625
 626        ch = notes->src->cycles_hist;
 627        for (unsigned int i = 0; i < symbol__size(he->ms.sym); i++) {
 628                if (ch[i].num_aggr) {
 629                        struct block_info *bi;
 630                        struct hist_entry *he_block;
 631
 632                        bi = block_info__new();
 633                        if (!bi)
 634                                return -1;
 635
 636                        init_block_info(bi, he->ms.sym, &ch[i], i);
 637                        he_block = hists__add_entry_block(&bh->block_hists,
 638                                                          &dummy_al, bi);
 639                        if (!he_block) {
 640                                block_info__put(bi);
 641                                return -1;
 642                        }
 643                }
 644        }
 645
 646        return 0;
 647}
 648
 649static int block_pair_cmp(struct hist_entry *a, struct hist_entry *b)
 650{
 651        struct block_info *bi_a = a->block_info;
 652        struct block_info *bi_b = b->block_info;
 653        int cmp;
 654
 655        if (!bi_a->sym || !bi_b->sym)
 656                return -1;
 657
 658        cmp = strcmp(bi_a->sym->name, bi_b->sym->name);
 659
 660        if ((!cmp) && (bi_a->start == bi_b->start) && (bi_a->end == bi_b->end))
 661                return 0;
 662
 663        return -1;
 664}
 665
 666static struct hist_entry *get_block_pair(struct hist_entry *he,
 667                                         struct hists *hists_pair)
 668{
 669        struct rb_root_cached *root = hists_pair->entries_in;
 670        struct rb_node *next = rb_first_cached(root);
 671        int cmp;
 672
 673        while (next != NULL) {
 674                struct hist_entry *he_pair = rb_entry(next, struct hist_entry,
 675                                                      rb_node_in);
 676
 677                next = rb_next(&he_pair->rb_node_in);
 678
 679                cmp = block_pair_cmp(he_pair, he);
 680                if (!cmp)
 681                        return he_pair;
 682        }
 683
 684        return NULL;
 685}
 686
 687static void compute_cycles_diff(struct hist_entry *he,
 688                                struct hist_entry *pair)
 689{
 690        pair->diff.computed = true;
 691        if (pair->block_info->num && he->block_info->num) {
 692                pair->diff.cycles =
 693                        pair->block_info->cycles_aggr / pair->block_info->num_aggr -
 694                        he->block_info->cycles_aggr / he->block_info->num_aggr;
 695        }
 696}
 697
 698static void block_hists_match(struct hists *hists_base,
 699                              struct hists *hists_pair)
 700{
 701        struct rb_root_cached *root = hists_base->entries_in;
 702        struct rb_node *next = rb_first_cached(root);
 703
 704        while (next != NULL) {
 705                struct hist_entry *he = rb_entry(next, struct hist_entry,
 706                                                 rb_node_in);
 707                struct hist_entry *pair = get_block_pair(he, hists_pair);
 708
 709                next = rb_next(&he->rb_node_in);
 710
 711                if (pair) {
 712                        hist_entry__add_pair(pair, he);
 713                        compute_cycles_diff(he, pair);
 714                }
 715        }
 716}
 717
 718static int filter_cb(struct hist_entry *he, void *arg __maybe_unused)
 719{
 720        /* Skip the calculation of column length in output_resort */
 721        he->filtered = true;
 722        return 0;
 723}
 724
 725static void hists__precompute(struct hists *hists)
 726{
 727        struct rb_root_cached *root;
 728        struct rb_node *next;
 729
 730        if (hists__has(hists, need_collapse))
 731                root = &hists->entries_collapsed;
 732        else
 733                root = hists->entries_in;
 734
 735        next = rb_first_cached(root);
 736        while (next != NULL) {
 737                struct block_hist *bh, *pair_bh;
 738                struct hist_entry *he, *pair;
 739                struct data__file *d;
 740                int i;
 741
 742                he   = rb_entry(next, struct hist_entry, rb_node_in);
 743                next = rb_next(&he->rb_node_in);
 744
 745                if (compute == COMPUTE_CYCLES)
 746                        process_block_per_sym(he);
 747
 748                data__for_each_file_new(i, d) {
 749                        pair = get_pair_data(he, d);
 750                        if (!pair)
 751                                continue;
 752
 753                        switch (compute) {
 754                        case COMPUTE_DELTA:
 755                        case COMPUTE_DELTA_ABS:
 756                                compute_delta(he, pair);
 757                                break;
 758                        case COMPUTE_RATIO:
 759                                compute_ratio(he, pair);
 760                                break;
 761                        case COMPUTE_WEIGHTED_DIFF:
 762                                compute_wdiff(he, pair);
 763                                break;
 764                        case COMPUTE_CYCLES:
 765                                process_block_per_sym(pair);
 766                                bh = container_of(he, struct block_hist, he);
 767                                pair_bh = container_of(pair, struct block_hist,
 768                                                       he);
 769
 770                                if (bh->valid && pair_bh->valid) {
 771                                        block_hists_match(&bh->block_hists,
 772                                                          &pair_bh->block_hists);
 773                                        hists__output_resort_cb(&pair_bh->block_hists,
 774                                                                NULL, filter_cb);
 775                                }
 776                                break;
 777                        default:
 778                                BUG_ON(1);
 779                        }
 780                }
 781        }
 782}
 783
 784static int64_t cmp_doubles(double l, double r)
 785{
 786        if (l > r)
 787                return -1;
 788        else if (l < r)
 789                return 1;
 790        else
 791                return 0;
 792}
 793
 794static int64_t
 795__hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
 796                        int c)
 797{
 798        switch (c) {
 799        case COMPUTE_DELTA:
 800        {
 801                double l = left->diff.period_ratio_delta;
 802                double r = right->diff.period_ratio_delta;
 803
 804                return cmp_doubles(l, r);
 805        }
 806        case COMPUTE_DELTA_ABS:
 807        {
 808                double l = fabs(left->diff.period_ratio_delta);
 809                double r = fabs(right->diff.period_ratio_delta);
 810
 811                return cmp_doubles(l, r);
 812        }
 813        case COMPUTE_RATIO:
 814        {
 815                double l = left->diff.period_ratio;
 816                double r = right->diff.period_ratio;
 817
 818                return cmp_doubles(l, r);
 819        }
 820        case COMPUTE_WEIGHTED_DIFF:
 821        {
 822                s64 l = left->diff.wdiff;
 823                s64 r = right->diff.wdiff;
 824
 825                return r - l;
 826        }
 827        default:
 828                BUG_ON(1);
 829        }
 830
 831        return 0;
 832}
 833
 834static int64_t
 835hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
 836                        int c, int sort_idx)
 837{
 838        bool pairs_left  = hist_entry__has_pairs(left);
 839        bool pairs_right = hist_entry__has_pairs(right);
 840        struct hist_entry *p_right, *p_left;
 841
 842        if (!pairs_left && !pairs_right)
 843                return 0;
 844
 845        if (!pairs_left || !pairs_right)
 846                return pairs_left ? -1 : 1;
 847
 848        p_left  = get_pair_data(left,  &data__files[sort_idx]);
 849        p_right = get_pair_data(right, &data__files[sort_idx]);
 850
 851        if (!p_left && !p_right)
 852                return 0;
 853
 854        if (!p_left || !p_right)
 855                return p_left ? -1 : 1;
 856
 857        /*
 858         * We have 2 entries of same kind, let's
 859         * make the data comparison.
 860         */
 861        return __hist_entry__cmp_compute(p_left, p_right, c);
 862}
 863
 864static int64_t
 865hist_entry__cmp_compute_idx(struct hist_entry *left, struct hist_entry *right,
 866                            int c, int sort_idx)
 867{
 868        struct hist_entry *p_right, *p_left;
 869
 870        p_left  = get_pair_data(left,  &data__files[sort_idx]);
 871        p_right = get_pair_data(right, &data__files[sort_idx]);
 872
 873        if (!p_left && !p_right)
 874                return 0;
 875
 876        if (!p_left || !p_right)
 877                return p_left ? -1 : 1;
 878
 879        if (c != COMPUTE_DELTA && c != COMPUTE_DELTA_ABS) {
 880                /*
 881                 * The delta can be computed without the baseline, but
 882                 * others are not.  Put those entries which have no
 883                 * values below.
 884                 */
 885                if (left->dummy && right->dummy)
 886                        return 0;
 887
 888                if (left->dummy || right->dummy)
 889                        return left->dummy ? 1 : -1;
 890        }
 891
 892        return __hist_entry__cmp_compute(p_left, p_right, c);
 893}
 894
 895static int64_t
 896hist_entry__cmp_nop(struct perf_hpp_fmt *fmt __maybe_unused,
 897                    struct hist_entry *left __maybe_unused,
 898                    struct hist_entry *right __maybe_unused)
 899{
 900        return 0;
 901}
 902
 903static int64_t
 904hist_entry__cmp_baseline(struct perf_hpp_fmt *fmt __maybe_unused,
 905                         struct hist_entry *left, struct hist_entry *right)
 906{
 907        if (left->stat.period == right->stat.period)
 908                return 0;
 909        return left->stat.period > right->stat.period ? 1 : -1;
 910}
 911
 912static int64_t
 913hist_entry__cmp_delta(struct perf_hpp_fmt *fmt,
 914                      struct hist_entry *left, struct hist_entry *right)
 915{
 916        struct data__file *d = fmt_to_data_file(fmt);
 917
 918        return hist_entry__cmp_compute(right, left, COMPUTE_DELTA, d->idx);
 919}
 920
 921static int64_t
 922hist_entry__cmp_delta_abs(struct perf_hpp_fmt *fmt,
 923                      struct hist_entry *left, struct hist_entry *right)
 924{
 925        struct data__file *d = fmt_to_data_file(fmt);
 926
 927        return hist_entry__cmp_compute(right, left, COMPUTE_DELTA_ABS, d->idx);
 928}
 929
 930static int64_t
 931hist_entry__cmp_ratio(struct perf_hpp_fmt *fmt,
 932                      struct hist_entry *left, struct hist_entry *right)
 933{
 934        struct data__file *d = fmt_to_data_file(fmt);
 935
 936        return hist_entry__cmp_compute(right, left, COMPUTE_RATIO, d->idx);
 937}
 938
 939static int64_t
 940hist_entry__cmp_wdiff(struct perf_hpp_fmt *fmt,
 941                      struct hist_entry *left, struct hist_entry *right)
 942{
 943        struct data__file *d = fmt_to_data_file(fmt);
 944
 945        return hist_entry__cmp_compute(right, left, COMPUTE_WEIGHTED_DIFF, d->idx);
 946}
 947
 948static int64_t
 949hist_entry__cmp_delta_idx(struct perf_hpp_fmt *fmt __maybe_unused,
 950                          struct hist_entry *left, struct hist_entry *right)
 951{
 952        return hist_entry__cmp_compute_idx(right, left, COMPUTE_DELTA,
 953                                           sort_compute);
 954}
 955
 956static int64_t
 957hist_entry__cmp_delta_abs_idx(struct perf_hpp_fmt *fmt __maybe_unused,
 958                              struct hist_entry *left, struct hist_entry *right)
 959{
 960        return hist_entry__cmp_compute_idx(right, left, COMPUTE_DELTA_ABS,
 961                                           sort_compute);
 962}
 963
 964static int64_t
 965hist_entry__cmp_ratio_idx(struct perf_hpp_fmt *fmt __maybe_unused,
 966                          struct hist_entry *left, struct hist_entry *right)
 967{
 968        return hist_entry__cmp_compute_idx(right, left, COMPUTE_RATIO,
 969                                           sort_compute);
 970}
 971
 972static int64_t
 973hist_entry__cmp_wdiff_idx(struct perf_hpp_fmt *fmt __maybe_unused,
 974                          struct hist_entry *left, struct hist_entry *right)
 975{
 976        return hist_entry__cmp_compute_idx(right, left, COMPUTE_WEIGHTED_DIFF,
 977                                           sort_compute);
 978}
 979
 980static void hists__process(struct hists *hists)
 981{
 982        if (show_baseline_only)
 983                hists__baseline_only(hists);
 984
 985        hists__precompute(hists);
 986        hists__output_resort(hists, NULL);
 987
 988        if (compute == COMPUTE_CYCLES)
 989                symbol_conf.report_block = true;
 990
 991        hists__fprintf(hists, !quiet, 0, 0, 0, stdout,
 992                       !symbol_conf.use_callchain);
 993}
 994
 995static void data__fprintf(void)
 996{
 997        struct data__file *d;
 998        int i;
 999
1000        fprintf(stdout, "# Data files:\n");
1001
1002        data__for_each_file(i, d)
1003                fprintf(stdout, "#  [%d] %s %s\n",
1004                        d->idx, d->data.path,
1005                        !d->idx ? "(Baseline)" : "");
1006
1007        fprintf(stdout, "#\n");
1008}
1009
1010static void data_process(void)
1011{
1012        struct perf_evlist *evlist_base = data__files[0].session->evlist;
1013        struct perf_evsel *evsel_base;
1014        bool first = true;
1015
1016        evlist__for_each_entry(evlist_base, evsel_base) {
1017                struct hists *hists_base = evsel__hists(evsel_base);
1018                struct data__file *d;
1019                int i;
1020
1021                data__for_each_file_new(i, d) {
1022                        struct perf_evlist *evlist = d->session->evlist;
1023                        struct perf_evsel *evsel;
1024                        struct hists *hists;
1025
1026                        evsel = evsel_match(evsel_base, evlist);
1027                        if (!evsel)
1028                                continue;
1029
1030                        hists = evsel__hists(evsel);
1031                        d->hists = hists;
1032
1033                        hists__match(hists_base, hists);
1034
1035                        if (!show_baseline_only)
1036                                hists__link(hists_base, hists);
1037                }
1038
1039                if (!quiet) {
1040                        fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
1041                                perf_evsel__name(evsel_base));
1042                }
1043
1044                first = false;
1045
1046                if (verbose > 0 || ((data__files_cnt > 2) && !quiet))
1047                        data__fprintf();
1048
1049                /* Don't sort callchain for perf diff */
1050                perf_evsel__reset_sample_bit(evsel_base, CALLCHAIN);
1051
1052                hists__process(hists_base);
1053        }
1054}
1055
1056static void data__free(struct data__file *d)
1057{
1058        int col;
1059
1060        for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
1061                struct diff_hpp_fmt *fmt = &d->fmt[col];
1062
1063                zfree(&fmt->header);
1064        }
1065}
1066
1067static int abstime_str_dup(char **pstr)
1068{
1069        char *str = NULL;
1070
1071        if (pdiff.time_str && strchr(pdiff.time_str, ':')) {
1072                str = strdup(pdiff.time_str);
1073                if (!str)
1074                        return -ENOMEM;
1075        }
1076
1077        *pstr = str;
1078        return 0;
1079}
1080
1081static int parse_absolute_time(struct data__file *d, char **pstr)
1082{
1083        char *p = *pstr;
1084        int ret;
1085
1086        /*
1087         * Absolute timestamp for one file has the format: a.b,c.d
1088         * For multiple files, the format is: a.b,c.d:a.b,c.d
1089         */
1090        p = strchr(*pstr, ':');
1091        if (p) {
1092                if (p == *pstr) {
1093                        pr_err("Invalid time string\n");
1094                        return -EINVAL;
1095                }
1096
1097                *p = 0;
1098                p++;
1099                if (*p == 0) {
1100                        pr_err("Invalid time string\n");
1101                        return -EINVAL;
1102                }
1103        }
1104
1105        ret = perf_time__parse_for_ranges(*pstr, d->session,
1106                                          &pdiff.ptime_range,
1107                                          &pdiff.range_size,
1108                                          &pdiff.range_num);
1109        if (ret < 0)
1110                return ret;
1111
1112        if (!p || *p == 0)
1113                *pstr = NULL;
1114        else
1115                *pstr = p;
1116
1117        return ret;
1118}
1119
1120static int parse_percent_time(struct data__file *d)
1121{
1122        int ret;
1123
1124        ret = perf_time__parse_for_ranges(pdiff.time_str, d->session,
1125                                          &pdiff.ptime_range,
1126                                          &pdiff.range_size,
1127                                          &pdiff.range_num);
1128        return ret;
1129}
1130
1131static int parse_time_str(struct data__file *d, char *abstime_ostr,
1132                           char **pabstime_tmp)
1133{
1134        int ret = 0;
1135
1136        if (abstime_ostr)
1137                ret = parse_absolute_time(d, pabstime_tmp);
1138        else if (pdiff.time_str)
1139                ret = parse_percent_time(d);
1140
1141        return ret;
1142}
1143
1144static int check_file_brstack(void)
1145{
1146        struct data__file *d;
1147        bool has_br_stack;
1148        int i;
1149
1150        data__for_each_file(i, d) {
1151                d->session = perf_session__new(&d->data, false, &pdiff.tool);
1152                if (!d->session) {
1153                        pr_err("Failed to open %s\n", d->data.path);
1154                        return -1;
1155                }
1156
1157                has_br_stack = perf_header__has_feat(&d->session->header,
1158                                                     HEADER_BRANCH_STACK);
1159                perf_session__delete(d->session);
1160                if (!has_br_stack)
1161                        return 0;
1162        }
1163
1164        /* Set only all files having branch stacks */
1165        pdiff.has_br_stack = true;
1166        return 0;
1167}
1168
1169static int __cmd_diff(void)
1170{
1171        struct data__file *d;
1172        int ret, i;
1173        char *abstime_ostr, *abstime_tmp;
1174
1175        ret = abstime_str_dup(&abstime_ostr);
1176        if (ret)
1177                return ret;
1178
1179        abstime_tmp = abstime_ostr;
1180        ret = -EINVAL;
1181
1182        data__for_each_file(i, d) {
1183                d->session = perf_session__new(&d->data, false, &pdiff.tool);
1184                if (!d->session) {
1185                        pr_err("Failed to open %s\n", d->data.path);
1186                        ret = -1;
1187                        goto out_delete;
1188                }
1189
1190                if (pdiff.time_str) {
1191                        ret = parse_time_str(d, abstime_ostr, &abstime_tmp);
1192                        if (ret < 0)
1193                                goto out_delete;
1194                }
1195
1196                if (cpu_list) {
1197                        ret = perf_session__cpu_bitmap(d->session, cpu_list,
1198                                                       cpu_bitmap);
1199                        if (ret < 0)
1200                                goto out_delete;
1201                }
1202
1203                ret = perf_session__process_events(d->session);
1204                if (ret) {
1205                        pr_err("Failed to process %s\n", d->data.path);
1206                        goto out_delete;
1207                }
1208
1209                perf_evlist__collapse_resort(d->session->evlist);
1210
1211                if (pdiff.ptime_range)
1212                        zfree(&pdiff.ptime_range);
1213        }
1214
1215        data_process();
1216
1217 out_delete:
1218        data__for_each_file(i, d) {
1219                perf_session__delete(d->session);
1220                data__free(d);
1221        }
1222
1223        free(data__files);
1224
1225        if (pdiff.ptime_range)
1226                zfree(&pdiff.ptime_range);
1227
1228        if (abstime_ostr)
1229                free(abstime_ostr);
1230
1231        return ret;
1232}
1233
1234static const char * const diff_usage[] = {
1235        "perf diff [<options>] [old_file] [new_file]",
1236        NULL,
1237};
1238
1239static const struct option options[] = {
1240        OPT_INCR('v', "verbose", &verbose,
1241                    "be more verbose (show symbol address, etc)"),
1242        OPT_BOOLEAN('q', "quiet", &quiet, "Do not show any message"),
1243        OPT_BOOLEAN('b', "baseline-only", &show_baseline_only,
1244                    "Show only items with match in baseline"),
1245        OPT_CALLBACK('c', "compute", &compute,
1246                     "delta,delta-abs,ratio,wdiff:w1,w2 (default delta-abs),cycles",
1247                     "Entries differential computation selection",
1248                     setup_compute),
1249        OPT_BOOLEAN('p', "period", &show_period,
1250                    "Show period values."),
1251        OPT_BOOLEAN('F', "formula", &show_formula,
1252                    "Show formula."),
1253        OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
1254                    "dump raw trace in ASCII"),
1255        OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
1256        OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
1257                   "file", "kallsyms pathname"),
1258        OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
1259                    "load module symbols - WARNING: use only with -k and LIVE kernel"),
1260        OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
1261                   "only consider symbols in these dsos"),
1262        OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
1263                   "only consider symbols in these comms"),
1264        OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
1265                   "only consider these symbols"),
1266        OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
1267                   "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
1268                   " Please refer the man page for the complete list."),
1269        OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator",
1270                   "separator for columns, no spaces will be added between "
1271                   "columns '.' is reserved."),
1272        OPT_CALLBACK(0, "symfs", NULL, "directory",
1273                     "Look for files with symbols relative to this directory",
1274                     symbol__config_symfs),
1275        OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
1276        OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
1277                     "How to display percentage of filtered entries", parse_filter_percentage),
1278        OPT_STRING(0, "time", &pdiff.time_str, "str",
1279                   "Time span (time percent or absolute timestamp)"),
1280        OPT_STRING(0, "cpu", &cpu_list, "cpu", "list of cpus to profile"),
1281        OPT_STRING(0, "pid", &symbol_conf.pid_list_str, "pid[,pid...]",
1282                   "only consider symbols in these pids"),
1283        OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
1284                   "only consider symbols in these tids"),
1285        OPT_END()
1286};
1287
1288static double baseline_percent(struct hist_entry *he)
1289{
1290        u64 total = hists__total_period(he->hists);
1291
1292        return 100.0 * he->stat.period / total;
1293}
1294
1295static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
1296                               struct perf_hpp *hpp, struct hist_entry *he)
1297{
1298        struct diff_hpp_fmt *dfmt =
1299                container_of(fmt, struct diff_hpp_fmt, fmt);
1300        double percent = baseline_percent(he);
1301        char pfmt[20] = " ";
1302
1303        if (!he->dummy) {
1304                scnprintf(pfmt, 20, "%%%d.2f%%%%", dfmt->header_width - 1);
1305                return percent_color_snprintf(hpp->buf, hpp->size,
1306                                              pfmt, percent);
1307        } else
1308                return scnprintf(hpp->buf, hpp->size, "%*s",
1309                                 dfmt->header_width, pfmt);
1310}
1311
1312static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size)
1313{
1314        double percent = baseline_percent(he);
1315        const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
1316        int ret = 0;
1317
1318        if (!he->dummy)
1319                ret = scnprintf(buf, size, fmt, percent);
1320
1321        return ret;
1322}
1323
1324static int cycles_printf(struct hist_entry *he, struct hist_entry *pair,
1325                         struct perf_hpp *hpp, int width)
1326{
1327        struct block_hist *bh = container_of(he, struct block_hist, he);
1328        struct block_hist *bh_pair = container_of(pair, struct block_hist, he);
1329        struct hist_entry *block_he;
1330        struct block_info *bi;
1331        char buf[128];
1332        char *start_line, *end_line;
1333
1334        block_he = hists__get_entry(&bh_pair->block_hists, bh->block_idx);
1335        if (!block_he) {
1336                hpp->skip = true;
1337                return 0;
1338        }
1339
1340        /*
1341         * Avoid printing the warning "addr2line_init failed for ..."
1342         */
1343        symbol_conf.disable_add2line_warn = true;
1344
1345        bi = block_he->block_info;
1346
1347        start_line = map__srcline(he->ms.map, bi->sym->start + bi->start,
1348                                  he->ms.sym);
1349
1350        end_line = map__srcline(he->ms.map, bi->sym->start + bi->end,
1351                                he->ms.sym);
1352
1353        if ((start_line != SRCLINE_UNKNOWN) && (end_line != SRCLINE_UNKNOWN)) {
1354                scnprintf(buf, sizeof(buf), "[%s -> %s] %4ld",
1355                          start_line, end_line, block_he->diff.cycles);
1356        } else {
1357                scnprintf(buf, sizeof(buf), "[%7lx -> %7lx] %4ld",
1358                          bi->start, bi->end, block_he->diff.cycles);
1359        }
1360
1361        free_srcline(start_line);
1362        free_srcline(end_line);
1363
1364        return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
1365}
1366
1367static int __hpp__color_compare(struct perf_hpp_fmt *fmt,
1368                                struct perf_hpp *hpp, struct hist_entry *he,
1369                                int comparison_method)
1370{
1371        struct diff_hpp_fmt *dfmt =
1372                container_of(fmt, struct diff_hpp_fmt, fmt);
1373        struct hist_entry *pair = get_pair_fmt(he, dfmt);
1374        double diff;
1375        s64 wdiff;
1376        char pfmt[20] = " ";
1377
1378        if (!pair) {
1379                if (comparison_method == COMPUTE_CYCLES) {
1380                        struct block_hist *bh;
1381
1382                        bh = container_of(he, struct block_hist, he);
1383                        if (bh->block_idx)
1384                                hpp->skip = true;
1385                }
1386
1387                goto no_print;
1388        }
1389
1390        switch (comparison_method) {
1391        case COMPUTE_DELTA:
1392                if (pair->diff.computed)
1393                        diff = pair->diff.period_ratio_delta;
1394                else
1395                        diff = compute_delta(he, pair);
1396
1397                scnprintf(pfmt, 20, "%%%+d.2f%%%%", dfmt->header_width - 1);
1398                return percent_color_snprintf(hpp->buf, hpp->size,
1399                                        pfmt, diff);
1400        case COMPUTE_RATIO:
1401                if (he->dummy)
1402                        goto dummy_print;
1403                if (pair->diff.computed)
1404                        diff = pair->diff.period_ratio;
1405                else
1406                        diff = compute_ratio(he, pair);
1407
1408                scnprintf(pfmt, 20, "%%%d.6f", dfmt->header_width);
1409                return value_color_snprintf(hpp->buf, hpp->size,
1410                                        pfmt, diff);
1411        case COMPUTE_WEIGHTED_DIFF:
1412                if (he->dummy)
1413                        goto dummy_print;
1414                if (pair->diff.computed)
1415                        wdiff = pair->diff.wdiff;
1416                else
1417                        wdiff = compute_wdiff(he, pair);
1418
1419                scnprintf(pfmt, 20, "%%14ld", dfmt->header_width);
1420                return color_snprintf(hpp->buf, hpp->size,
1421                                get_percent_color(wdiff),
1422                                pfmt, wdiff);
1423        case COMPUTE_CYCLES:
1424                return cycles_printf(he, pair, hpp, dfmt->header_width);
1425        default:
1426                BUG_ON(1);
1427        }
1428dummy_print:
1429        return scnprintf(hpp->buf, hpp->size, "%*s",
1430                        dfmt->header_width, "N/A");
1431no_print:
1432        return scnprintf(hpp->buf, hpp->size, "%*s",
1433                        dfmt->header_width, pfmt);
1434}
1435
1436static int hpp__color_delta(struct perf_hpp_fmt *fmt,
1437                        struct perf_hpp *hpp, struct hist_entry *he)
1438{
1439        return __hpp__color_compare(fmt, hpp, he, COMPUTE_DELTA);
1440}
1441
1442static int hpp__color_ratio(struct perf_hpp_fmt *fmt,
1443                        struct perf_hpp *hpp, struct hist_entry *he)
1444{
1445        return __hpp__color_compare(fmt, hpp, he, COMPUTE_RATIO);
1446}
1447
1448static int hpp__color_wdiff(struct perf_hpp_fmt *fmt,
1449                        struct perf_hpp *hpp, struct hist_entry *he)
1450{
1451        return __hpp__color_compare(fmt, hpp, he, COMPUTE_WEIGHTED_DIFF);
1452}
1453
1454static int hpp__color_cycles(struct perf_hpp_fmt *fmt,
1455                             struct perf_hpp *hpp, struct hist_entry *he)
1456{
1457        return __hpp__color_compare(fmt, hpp, he, COMPUTE_CYCLES);
1458}
1459
1460static void
1461hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
1462{
1463        switch (idx) {
1464        case PERF_HPP_DIFF__PERIOD_BASELINE:
1465                scnprintf(buf, size, "%" PRIu64, he->stat.period);
1466                break;
1467
1468        default:
1469                break;
1470        }
1471}
1472
1473static void
1474hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,
1475                int idx, char *buf, size_t size)
1476{
1477        double diff;
1478        double ratio;
1479        s64 wdiff;
1480
1481        switch (idx) {
1482        case PERF_HPP_DIFF__DELTA:
1483        case PERF_HPP_DIFF__DELTA_ABS:
1484                if (pair->diff.computed)
1485                        diff = pair->diff.period_ratio_delta;
1486                else
1487                        diff = compute_delta(he, pair);
1488
1489                scnprintf(buf, size, "%+4.2F%%", diff);
1490                break;
1491
1492        case PERF_HPP_DIFF__RATIO:
1493                /* No point for ratio number if we are dummy.. */
1494                if (he->dummy) {
1495                        scnprintf(buf, size, "N/A");
1496                        break;
1497                }
1498
1499                if (pair->diff.computed)
1500                        ratio = pair->diff.period_ratio;
1501                else
1502                        ratio = compute_ratio(he, pair);
1503
1504                if (ratio > 0.0)
1505                        scnprintf(buf, size, "%14.6F", ratio);
1506                break;
1507
1508        case PERF_HPP_DIFF__WEIGHTED_DIFF:
1509                /* No point for wdiff number if we are dummy.. */
1510                if (he->dummy) {
1511                        scnprintf(buf, size, "N/A");
1512                        break;
1513                }
1514
1515                if (pair->diff.computed)
1516                        wdiff = pair->diff.wdiff;
1517                else
1518                        wdiff = compute_wdiff(he, pair);
1519
1520                if (wdiff != 0)
1521                        scnprintf(buf, size, "%14ld", wdiff);
1522                break;
1523
1524        case PERF_HPP_DIFF__FORMULA:
1525                formula_fprintf(he, pair, buf, size);
1526                break;
1527
1528        case PERF_HPP_DIFF__PERIOD:
1529                scnprintf(buf, size, "%" PRIu64, pair->stat.period);
1530                break;
1531
1532        default:
1533                BUG_ON(1);
1534        };
1535}
1536
1537static void
1538__hpp__entry_global(struct hist_entry *he, struct diff_hpp_fmt *dfmt,
1539                    char *buf, size_t size)
1540{
1541        struct hist_entry *pair = get_pair_fmt(he, dfmt);
1542        int idx = dfmt->idx;
1543
1544        /* baseline is special */
1545        if (idx == PERF_HPP_DIFF__BASELINE)
1546                hpp__entry_baseline(he, buf, size);
1547        else {
1548                if (pair)
1549                        hpp__entry_pair(he, pair, idx, buf, size);
1550                else
1551                        hpp__entry_unpair(he, idx, buf, size);
1552        }
1553}
1554
1555static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
1556                             struct hist_entry *he)
1557{
1558        struct diff_hpp_fmt *dfmt =
1559                container_of(_fmt, struct diff_hpp_fmt, fmt);
1560        char buf[MAX_COL_WIDTH] = " ";
1561
1562        __hpp__entry_global(he, dfmt, buf, MAX_COL_WIDTH);
1563
1564        if (symbol_conf.field_sep)
1565                return scnprintf(hpp->buf, hpp->size, "%s", buf);
1566        else
1567                return scnprintf(hpp->buf, hpp->size, "%*s",
1568                                 dfmt->header_width, buf);
1569}
1570
1571static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1572                       struct hists *hists __maybe_unused,
1573                       int line __maybe_unused,
1574                       int *span __maybe_unused)
1575{
1576        struct diff_hpp_fmt *dfmt =
1577                container_of(fmt, struct diff_hpp_fmt, fmt);
1578
1579        BUG_ON(!dfmt->header);
1580        return scnprintf(hpp->buf, hpp->size, dfmt->header);
1581}
1582
1583static int hpp__width(struct perf_hpp_fmt *fmt,
1584                      struct perf_hpp *hpp __maybe_unused,
1585                      struct hists *hists __maybe_unused)
1586{
1587        struct diff_hpp_fmt *dfmt =
1588                container_of(fmt, struct diff_hpp_fmt, fmt);
1589
1590        BUG_ON(dfmt->header_width <= 0);
1591        return dfmt->header_width;
1592}
1593
1594static void init_header(struct data__file *d, struct diff_hpp_fmt *dfmt)
1595{
1596#define MAX_HEADER_NAME 100
1597        char buf_indent[MAX_HEADER_NAME];
1598        char buf[MAX_HEADER_NAME];
1599        const char *header = NULL;
1600        int width = 0;
1601
1602        BUG_ON(dfmt->idx >= PERF_HPP_DIFF__MAX_INDEX);
1603        header = columns[dfmt->idx].name;
1604        width  = columns[dfmt->idx].width;
1605
1606        /* Only our defined HPP fmts should appear here. */
1607        BUG_ON(!header);
1608
1609        if (data__files_cnt > 2)
1610                scnprintf(buf, MAX_HEADER_NAME, "%s/%d", header, d->idx);
1611
1612#define NAME (data__files_cnt > 2 ? buf : header)
1613        dfmt->header_width = width;
1614        width = (int) strlen(NAME);
1615        if (dfmt->header_width < width)
1616                dfmt->header_width = width;
1617
1618        scnprintf(buf_indent, MAX_HEADER_NAME, "%*s",
1619                  dfmt->header_width, NAME);
1620
1621        dfmt->header = strdup(buf_indent);
1622#undef MAX_HEADER_NAME
1623#undef NAME
1624}
1625
1626static void data__hpp_register(struct data__file *d, int idx)
1627{
1628        struct diff_hpp_fmt *dfmt = &d->fmt[idx];
1629        struct perf_hpp_fmt *fmt = &dfmt->fmt;
1630
1631        dfmt->idx = idx;
1632
1633        fmt->header = hpp__header;
1634        fmt->width  = hpp__width;
1635        fmt->entry  = hpp__entry_global;
1636        fmt->cmp    = hist_entry__cmp_nop;
1637        fmt->collapse = hist_entry__cmp_nop;
1638
1639        /* TODO more colors */
1640        switch (idx) {
1641        case PERF_HPP_DIFF__BASELINE:
1642                fmt->color = hpp__color_baseline;
1643                fmt->sort  = hist_entry__cmp_baseline;
1644                break;
1645        case PERF_HPP_DIFF__DELTA:
1646                fmt->color = hpp__color_delta;
1647                fmt->sort  = hist_entry__cmp_delta;
1648                break;
1649        case PERF_HPP_DIFF__RATIO:
1650                fmt->color = hpp__color_ratio;
1651                fmt->sort  = hist_entry__cmp_ratio;
1652                break;
1653        case PERF_HPP_DIFF__WEIGHTED_DIFF:
1654                fmt->color = hpp__color_wdiff;
1655                fmt->sort  = hist_entry__cmp_wdiff;
1656                break;
1657        case PERF_HPP_DIFF__DELTA_ABS:
1658                fmt->color = hpp__color_delta;
1659                fmt->sort  = hist_entry__cmp_delta_abs;
1660                break;
1661        case PERF_HPP_DIFF__CYCLES:
1662                fmt->color = hpp__color_cycles;
1663                fmt->sort  = hist_entry__cmp_nop;
1664                break;
1665        default:
1666                fmt->sort  = hist_entry__cmp_nop;
1667                break;
1668        }
1669
1670        init_header(d, dfmt);
1671        perf_hpp__column_register(fmt);
1672        perf_hpp__register_sort_field(fmt);
1673}
1674
1675static int ui_init(void)
1676{
1677        struct data__file *d;
1678        struct perf_hpp_fmt *fmt;
1679        int i;
1680
1681        data__for_each_file(i, d) {
1682
1683                /*
1684                 * Baseline or compute realted columns:
1685                 *
1686                 *   PERF_HPP_DIFF__BASELINE
1687                 *   PERF_HPP_DIFF__DELTA
1688                 *   PERF_HPP_DIFF__RATIO
1689                 *   PERF_HPP_DIFF__WEIGHTED_DIFF
1690                 */
1691                data__hpp_register(d, i ? compute_2_hpp[compute] :
1692                                          PERF_HPP_DIFF__BASELINE);
1693
1694                /*
1695                 * And the rest:
1696                 *
1697                 * PERF_HPP_DIFF__FORMULA
1698                 * PERF_HPP_DIFF__PERIOD
1699                 * PERF_HPP_DIFF__PERIOD_BASELINE
1700                 */
1701                if (show_formula && i)
1702                        data__hpp_register(d, PERF_HPP_DIFF__FORMULA);
1703
1704                if (show_period)
1705                        data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD :
1706                                                  PERF_HPP_DIFF__PERIOD_BASELINE);
1707        }
1708
1709        if (!sort_compute)
1710                return 0;
1711
1712        /*
1713         * Prepend an fmt to sort on columns at 'sort_compute' first.
1714         * This fmt is added only to the sort list but not to the
1715         * output fields list.
1716         *
1717         * Note that this column (data) can be compared twice - one
1718         * for this 'sort_compute' fmt and another for the normal
1719         * diff_hpp_fmt.  But it shouldn't a problem as most entries
1720         * will be sorted out by first try or baseline and comparing
1721         * is not a costly operation.
1722         */
1723        fmt = zalloc(sizeof(*fmt));
1724        if (fmt == NULL) {
1725                pr_err("Memory allocation failed\n");
1726                return -1;
1727        }
1728
1729        fmt->cmp      = hist_entry__cmp_nop;
1730        fmt->collapse = hist_entry__cmp_nop;
1731
1732        switch (compute) {
1733        case COMPUTE_DELTA:
1734                fmt->sort = hist_entry__cmp_delta_idx;
1735                break;
1736        case COMPUTE_RATIO:
1737                fmt->sort = hist_entry__cmp_ratio_idx;
1738                break;
1739        case COMPUTE_WEIGHTED_DIFF:
1740                fmt->sort = hist_entry__cmp_wdiff_idx;
1741                break;
1742        case COMPUTE_DELTA_ABS:
1743                fmt->sort = hist_entry__cmp_delta_abs_idx;
1744                break;
1745        case COMPUTE_CYCLES:
1746                /*
1747                 * Should set since 'fmt->sort' is called without
1748                 * checking valid during sorting
1749                 */
1750                fmt->sort = hist_entry__cmp_nop;
1751                break;
1752        default:
1753                BUG_ON(1);
1754        }
1755
1756        perf_hpp__prepend_sort_field(fmt);
1757        return 0;
1758}
1759
1760static int data_init(int argc, const char **argv)
1761{
1762        struct data__file *d;
1763        static const char *defaults[] = {
1764                "perf.data.old",
1765                "perf.data",
1766        };
1767        bool use_default = true;
1768        int i;
1769
1770        data__files_cnt = 2;
1771
1772        if (argc) {
1773                if (argc == 1)
1774                        defaults[1] = argv[0];
1775                else {
1776                        data__files_cnt = argc;
1777                        use_default = false;
1778                }
1779        } else if (perf_guest) {
1780                defaults[0] = "perf.data.host";
1781                defaults[1] = "perf.data.guest";
1782        }
1783
1784        if (sort_compute >= (unsigned int) data__files_cnt) {
1785                pr_err("Order option out of limit.\n");
1786                return -EINVAL;
1787        }
1788
1789        data__files = zalloc(sizeof(*data__files) * data__files_cnt);
1790        if (!data__files)
1791                return -ENOMEM;
1792
1793        data__for_each_file(i, d) {
1794                struct perf_data *data = &d->data;
1795
1796                data->path  = use_default ? defaults[i] : argv[i];
1797                data->mode  = PERF_DATA_MODE_READ,
1798                data->force = force,
1799
1800                d->idx  = i;
1801        }
1802
1803        return 0;
1804}
1805
1806static int diff__config(const char *var, const char *value,
1807                        void *cb __maybe_unused)
1808{
1809        if (!strcmp(var, "diff.order")) {
1810                int ret;
1811                if (perf_config_int(&ret, var, value) < 0)
1812                        return -1;
1813                sort_compute = ret;
1814                return 0;
1815        }
1816        if (!strcmp(var, "diff.compute")) {
1817                if (!strcmp(value, "delta")) {
1818                        compute = COMPUTE_DELTA;
1819                } else if (!strcmp(value, "delta-abs")) {
1820                        compute = COMPUTE_DELTA_ABS;
1821                } else if (!strcmp(value, "ratio")) {
1822                        compute = COMPUTE_RATIO;
1823                } else if (!strcmp(value, "wdiff")) {
1824                        compute = COMPUTE_WEIGHTED_DIFF;
1825                } else {
1826                        pr_err("Invalid compute method: %s\n", value);
1827                        return -1;
1828                }
1829        }
1830
1831        return 0;
1832}
1833
1834int cmd_diff(int argc, const char **argv)
1835{
1836        int ret = hists__init();
1837
1838        if (ret < 0)
1839                return ret;
1840
1841        perf_config(diff__config, NULL);
1842
1843        argc = parse_options(argc, argv, options, diff_usage, 0);
1844
1845        if (quiet)
1846                perf_quiet_option();
1847
1848        symbol__annotation_init();
1849
1850        if (symbol__init(NULL) < 0)
1851                return -1;
1852
1853        if (data_init(argc, argv) < 0)
1854                return -1;
1855
1856        if (check_file_brstack() < 0)
1857                return -1;
1858
1859        if (compute == COMPUTE_CYCLES && !pdiff.has_br_stack)
1860                return -1;
1861
1862        if (ui_init() < 0)
1863                return -1;
1864
1865        sort__mode = SORT_MODE__DIFF;
1866
1867        if (setup_sorting(NULL) < 0)
1868                usage_with_options(diff_usage, options);
1869
1870        setup_pager();
1871
1872        sort__setup_elide(NULL);
1873
1874        return __cmd_diff();
1875}
1876