linux/tools/perf/util/sort.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2#include <errno.h>
   3#include <inttypes.h>
   4#include <regex.h>
   5#include <linux/mman.h>
   6#include "sort.h"
   7#include "hist.h"
   8#include "comm.h"
   9#include "symbol.h"
  10#include "thread.h"
  11#include "evsel.h"
  12#include "evlist.h"
  13#include "strlist.h"
  14#include <traceevent/event-parse.h>
  15#include "mem-events.h"
  16#include "annotate.h"
  17#include <linux/kernel.h>
  18
  19regex_t         parent_regex;
  20const char      default_parent_pattern[] = "^sys_|^do_page_fault";
  21const char      *parent_pattern = default_parent_pattern;
  22const char      *default_sort_order = "comm,dso,symbol";
  23const char      default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cycles";
  24const char      default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
  25const char      default_top_sort_order[] = "dso,symbol";
  26const char      default_diff_sort_order[] = "dso,symbol";
  27const char      default_tracepoint_sort_order[] = "trace";
  28const char      *sort_order;
  29const char      *field_order;
  30regex_t         ignore_callees_regex;
  31int             have_ignore_callees = 0;
  32enum sort_mode  sort__mode = SORT_MODE__NORMAL;
  33
  34/*
  35 * Replaces all occurrences of a char used with the:
  36 *
  37 * -t, --field-separator
  38 *
  39 * option, that uses a special separator character and don't pad with spaces,
  40 * replacing all occurrences of this separator in symbol names (and other
  41 * output) with a '.' character, that thus it's the only non valid separator.
  42*/
  43static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...)
  44{
  45        int n;
  46        va_list ap;
  47
  48        va_start(ap, fmt);
  49        n = vsnprintf(bf, size, fmt, ap);
  50        if (symbol_conf.field_sep && n > 0) {
  51                char *sep = bf;
  52
  53                while (1) {
  54                        sep = strchr(sep, *symbol_conf.field_sep);
  55                        if (sep == NULL)
  56                                break;
  57                        *sep = '.';
  58                }
  59        }
  60        va_end(ap);
  61
  62        if (n >= (int)size)
  63                return size - 1;
  64        return n;
  65}
  66
  67static int64_t cmp_null(const void *l, const void *r)
  68{
  69        if (!l && !r)
  70                return 0;
  71        else if (!l)
  72                return -1;
  73        else
  74                return 1;
  75}
  76
  77/* --sort pid */
  78
  79static int64_t
  80sort__thread_cmp(struct hist_entry *left, struct hist_entry *right)
  81{
  82        return right->thread->tid - left->thread->tid;
  83}
  84
  85static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf,
  86                                       size_t size, unsigned int width)
  87{
  88        const char *comm = thread__comm_str(he->thread);
  89
  90        width = max(7U, width) - 8;
  91        return repsep_snprintf(bf, size, "%7d:%-*.*s", he->thread->tid,
  92                               width, width, comm ?: "");
  93}
  94
  95static int hist_entry__thread_filter(struct hist_entry *he, int type, const void *arg)
  96{
  97        const struct thread *th = arg;
  98
  99        if (type != HIST_FILTER__THREAD)
 100                return -1;
 101
 102        return th && he->thread != th;
 103}
 104
 105struct sort_entry sort_thread = {
 106        .se_header      = "    Pid:Command",
 107        .se_cmp         = sort__thread_cmp,
 108        .se_snprintf    = hist_entry__thread_snprintf,
 109        .se_filter      = hist_entry__thread_filter,
 110        .se_width_idx   = HISTC_THREAD,
 111};
 112
 113/* --sort comm */
 114
 115/*
 116 * We can't use pointer comparison in functions below,
 117 * because it gives different results based on pointer
 118 * values, which could break some sorting assumptions.
 119 */
 120static int64_t
 121sort__comm_cmp(struct hist_entry *left, struct hist_entry *right)
 122{
 123        return strcmp(comm__str(right->comm), comm__str(left->comm));
 124}
 125
 126static int64_t
 127sort__comm_collapse(struct hist_entry *left, struct hist_entry *right)
 128{
 129        return strcmp(comm__str(right->comm), comm__str(left->comm));
 130}
 131
 132static int64_t
 133sort__comm_sort(struct hist_entry *left, struct hist_entry *right)
 134{
 135        return strcmp(comm__str(right->comm), comm__str(left->comm));
 136}
 137
 138static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf,
 139                                     size_t size, unsigned int width)
 140{
 141        return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm));
 142}
 143
 144struct sort_entry sort_comm = {
 145        .se_header      = "Command",
 146        .se_cmp         = sort__comm_cmp,
 147        .se_collapse    = sort__comm_collapse,
 148        .se_sort        = sort__comm_sort,
 149        .se_snprintf    = hist_entry__comm_snprintf,
 150        .se_filter      = hist_entry__thread_filter,
 151        .se_width_idx   = HISTC_COMM,
 152};
 153
 154/* --sort dso */
 155
 156static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r)
 157{
 158        struct dso *dso_l = map_l ? map_l->dso : NULL;
 159        struct dso *dso_r = map_r ? map_r->dso : NULL;
 160        const char *dso_name_l, *dso_name_r;
 161
 162        if (!dso_l || !dso_r)
 163                return cmp_null(dso_r, dso_l);
 164
 165        if (verbose > 0) {
 166                dso_name_l = dso_l->long_name;
 167                dso_name_r = dso_r->long_name;
 168        } else {
 169                dso_name_l = dso_l->short_name;
 170                dso_name_r = dso_r->short_name;
 171        }
 172
 173        return strcmp(dso_name_l, dso_name_r);
 174}
 175
 176static int64_t
 177sort__dso_cmp(struct hist_entry *left, struct hist_entry *right)
 178{
 179        return _sort__dso_cmp(right->ms.map, left->ms.map);
 180}
 181
 182static int _hist_entry__dso_snprintf(struct map *map, char *bf,
 183                                     size_t size, unsigned int width)
 184{
 185        if (map && map->dso) {
 186                const char *dso_name = verbose > 0 ? map->dso->long_name :
 187                        map->dso->short_name;
 188                return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name);
 189        }
 190
 191        return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]");
 192}
 193
 194static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf,
 195                                    size_t size, unsigned int width)
 196{
 197        return _hist_entry__dso_snprintf(he->ms.map, bf, size, width);
 198}
 199
 200static int hist_entry__dso_filter(struct hist_entry *he, int type, const void *arg)
 201{
 202        const struct dso *dso = arg;
 203
 204        if (type != HIST_FILTER__DSO)
 205                return -1;
 206
 207        return dso && (!he->ms.map || he->ms.map->dso != dso);
 208}
 209
 210struct sort_entry sort_dso = {
 211        .se_header      = "Shared Object",
 212        .se_cmp         = sort__dso_cmp,
 213        .se_snprintf    = hist_entry__dso_snprintf,
 214        .se_filter      = hist_entry__dso_filter,
 215        .se_width_idx   = HISTC_DSO,
 216};
 217
 218/* --sort symbol */
 219
 220static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip)
 221{
 222        return (int64_t)(right_ip - left_ip);
 223}
 224
 225static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r)
 226{
 227        if (!sym_l || !sym_r)
 228                return cmp_null(sym_l, sym_r);
 229
 230        if (sym_l == sym_r)
 231                return 0;
 232
 233        if (sym_l->inlined || sym_r->inlined)
 234                return strcmp(sym_l->name, sym_r->name);
 235
 236        if (sym_l->start != sym_r->start)
 237                return (int64_t)(sym_r->start - sym_l->start);
 238
 239        return (int64_t)(sym_r->end - sym_l->end);
 240}
 241
 242static int64_t
 243sort__sym_cmp(struct hist_entry *left, struct hist_entry *right)
 244{
 245        int64_t ret;
 246
 247        if (!left->ms.sym && !right->ms.sym)
 248                return _sort__addr_cmp(left->ip, right->ip);
 249
 250        /*
 251         * comparing symbol address alone is not enough since it's a
 252         * relative address within a dso.
 253         */
 254        if (!hists__has(left->hists, dso) || hists__has(right->hists, dso)) {
 255                ret = sort__dso_cmp(left, right);
 256                if (ret != 0)
 257                        return ret;
 258        }
 259
 260        return _sort__sym_cmp(left->ms.sym, right->ms.sym);
 261}
 262
 263static int64_t
 264sort__sym_sort(struct hist_entry *left, struct hist_entry *right)
 265{
 266        if (!left->ms.sym || !right->ms.sym)
 267                return cmp_null(left->ms.sym, right->ms.sym);
 268
 269        return strcmp(right->ms.sym->name, left->ms.sym->name);
 270}
 271
 272static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym,
 273                                     u64 ip, char level, char *bf, size_t size,
 274                                     unsigned int width)
 275{
 276        size_t ret = 0;
 277
 278        if (verbose > 0) {
 279                char o = map ? dso__symtab_origin(map->dso) : '!';
 280                ret += repsep_snprintf(bf, size, "%-#*llx %c ",
 281                                       BITS_PER_LONG / 4 + 2, ip, o);
 282        }
 283
 284        ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level);
 285        if (sym && map) {
 286                if (sym->type == STT_OBJECT) {
 287                        ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name);
 288                        ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx",
 289                                        ip - map->unmap_ip(map, sym->start));
 290                } else {
 291                        ret += repsep_snprintf(bf + ret, size - ret, "%.*s",
 292                                               width - ret,
 293                                               sym->name);
 294                        if (sym->inlined)
 295                                ret += repsep_snprintf(bf + ret, size - ret,
 296                                                       " (inlined)");
 297                }
 298        } else {
 299                size_t len = BITS_PER_LONG / 4;
 300                ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx",
 301                                       len, ip);
 302        }
 303
 304        return ret;
 305}
 306
 307static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf,
 308                                    size_t size, unsigned int width)
 309{
 310        return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip,
 311                                         he->level, bf, size, width);
 312}
 313
 314static int hist_entry__sym_filter(struct hist_entry *he, int type, const void *arg)
 315{
 316        const char *sym = arg;
 317
 318        if (type != HIST_FILTER__SYMBOL)
 319                return -1;
 320
 321        return sym && (!he->ms.sym || !strstr(he->ms.sym->name, sym));
 322}
 323
 324struct sort_entry sort_sym = {
 325        .se_header      = "Symbol",
 326        .se_cmp         = sort__sym_cmp,
 327        .se_sort        = sort__sym_sort,
 328        .se_snprintf    = hist_entry__sym_snprintf,
 329        .se_filter      = hist_entry__sym_filter,
 330        .se_width_idx   = HISTC_SYMBOL,
 331};
 332
 333/* --sort srcline */
 334
 335char *hist_entry__srcline(struct hist_entry *he)
 336{
 337        return map__srcline(he->ms.map, he->ip, he->ms.sym);
 338}
 339
 340static int64_t
 341sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
 342{
 343        if (!left->srcline)
 344                left->srcline = hist_entry__srcline(left);
 345        if (!right->srcline)
 346                right->srcline = hist_entry__srcline(right);
 347
 348        return strcmp(right->srcline, left->srcline);
 349}
 350
 351static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
 352                                        size_t size, unsigned int width)
 353{
 354        if (!he->srcline)
 355                he->srcline = hist_entry__srcline(he);
 356
 357        return repsep_snprintf(bf, size, "%-.*s", width, he->srcline);
 358}
 359
 360struct sort_entry sort_srcline = {
 361        .se_header      = "Source:Line",
 362        .se_cmp         = sort__srcline_cmp,
 363        .se_snprintf    = hist_entry__srcline_snprintf,
 364        .se_width_idx   = HISTC_SRCLINE,
 365};
 366
 367/* --sort srcline_from */
 368
 369static char *addr_map_symbol__srcline(struct addr_map_symbol *ams)
 370{
 371        return map__srcline(ams->map, ams->al_addr, ams->sym);
 372}
 373
 374static int64_t
 375sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right)
 376{
 377        if (!left->branch_info->srcline_from)
 378                left->branch_info->srcline_from = addr_map_symbol__srcline(&left->branch_info->from);
 379
 380        if (!right->branch_info->srcline_from)
 381                right->branch_info->srcline_from = addr_map_symbol__srcline(&right->branch_info->from);
 382
 383        return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from);
 384}
 385
 386static int hist_entry__srcline_from_snprintf(struct hist_entry *he, char *bf,
 387                                        size_t size, unsigned int width)
 388{
 389        return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_from);
 390}
 391
 392struct sort_entry sort_srcline_from = {
 393        .se_header      = "From Source:Line",
 394        .se_cmp         = sort__srcline_from_cmp,
 395        .se_snprintf    = hist_entry__srcline_from_snprintf,
 396        .se_width_idx   = HISTC_SRCLINE_FROM,
 397};
 398
 399/* --sort srcline_to */
 400
 401static int64_t
 402sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right)
 403{
 404        if (!left->branch_info->srcline_to)
 405                left->branch_info->srcline_to = addr_map_symbol__srcline(&left->branch_info->to);
 406
 407        if (!right->branch_info->srcline_to)
 408                right->branch_info->srcline_to = addr_map_symbol__srcline(&right->branch_info->to);
 409
 410        return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to);
 411}
 412
 413static int hist_entry__srcline_to_snprintf(struct hist_entry *he, char *bf,
 414                                        size_t size, unsigned int width)
 415{
 416        return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_to);
 417}
 418
 419struct sort_entry sort_srcline_to = {
 420        .se_header      = "To Source:Line",
 421        .se_cmp         = sort__srcline_to_cmp,
 422        .se_snprintf    = hist_entry__srcline_to_snprintf,
 423        .se_width_idx   = HISTC_SRCLINE_TO,
 424};
 425
 426static int hist_entry__sym_ipc_snprintf(struct hist_entry *he, char *bf,
 427                                        size_t size, unsigned int width)
 428{
 429
 430        struct symbol *sym = he->ms.sym;
 431        struct map *map = he->ms.map;
 432        struct perf_evsel *evsel = hists_to_evsel(he->hists);
 433        struct annotation *notes;
 434        double ipc = 0.0, coverage = 0.0;
 435        char tmp[64];
 436
 437        if (!sym)
 438                return repsep_snprintf(bf, size, "%-*s", width, "-");
 439
 440        if (!sym->annotate2 && symbol__annotate2(sym, map, evsel,
 441                &annotation__default_options, NULL) < 0) {
 442                return 0;
 443        }
 444
 445        notes = symbol__annotation(sym);
 446
 447        if (notes->hit_cycles)
 448                ipc = notes->hit_insn / ((double)notes->hit_cycles);
 449
 450        if (notes->total_insn) {
 451                coverage = notes->cover_insn * 100.0 /
 452                        ((double)notes->total_insn);
 453        }
 454
 455        snprintf(tmp, sizeof(tmp), "%-5.2f [%5.1f%%]", ipc, coverage);
 456        return repsep_snprintf(bf, size, "%-*s", width, tmp);
 457}
 458
 459struct sort_entry sort_sym_ipc = {
 460        .se_header      = "IPC   [IPC Coverage]",
 461        .se_cmp         = sort__sym_cmp,
 462        .se_snprintf    = hist_entry__sym_ipc_snprintf,
 463        .se_width_idx   = HISTC_SYMBOL_IPC,
 464};
 465
 466static int hist_entry__sym_ipc_null_snprintf(struct hist_entry *he
 467                                             __maybe_unused,
 468                                             char *bf, size_t size,
 469                                             unsigned int width)
 470{
 471        char tmp[64];
 472
 473        snprintf(tmp, sizeof(tmp), "%-5s %2s", "-", "-");
 474        return repsep_snprintf(bf, size, "%-*s", width, tmp);
 475}
 476
 477struct sort_entry sort_sym_ipc_null = {
 478        .se_header      = "IPC   [IPC Coverage]",
 479        .se_cmp         = sort__sym_cmp,
 480        .se_snprintf    = hist_entry__sym_ipc_null_snprintf,
 481        .se_width_idx   = HISTC_SYMBOL_IPC,
 482};
 483
 484/* --sort srcfile */
 485
 486static char no_srcfile[1];
 487
 488static char *hist_entry__get_srcfile(struct hist_entry *e)
 489{
 490        char *sf, *p;
 491        struct map *map = e->ms.map;
 492
 493        if (!map)
 494                return no_srcfile;
 495
 496        sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip),
 497                         e->ms.sym, false, true, true, e->ip);
 498        if (!strcmp(sf, SRCLINE_UNKNOWN))
 499                return no_srcfile;
 500        p = strchr(sf, ':');
 501        if (p && *sf) {
 502                *p = 0;
 503                return sf;
 504        }
 505        free(sf);
 506        return no_srcfile;
 507}
 508
 509static int64_t
 510sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right)
 511{
 512        if (!left->srcfile)
 513                left->srcfile = hist_entry__get_srcfile(left);
 514        if (!right->srcfile)
 515                right->srcfile = hist_entry__get_srcfile(right);
 516
 517        return strcmp(right->srcfile, left->srcfile);
 518}
 519
 520static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf,
 521                                        size_t size, unsigned int width)
 522{
 523        if (!he->srcfile)
 524                he->srcfile = hist_entry__get_srcfile(he);
 525
 526        return repsep_snprintf(bf, size, "%-.*s", width, he->srcfile);
 527}
 528
 529struct sort_entry sort_srcfile = {
 530        .se_header      = "Source File",
 531        .se_cmp         = sort__srcfile_cmp,
 532        .se_snprintf    = hist_entry__srcfile_snprintf,
 533        .se_width_idx   = HISTC_SRCFILE,
 534};
 535
 536/* --sort parent */
 537
 538static int64_t
 539sort__parent_cmp(struct hist_entry *left, struct hist_entry *right)
 540{
 541        struct symbol *sym_l = left->parent;
 542        struct symbol *sym_r = right->parent;
 543
 544        if (!sym_l || !sym_r)
 545                return cmp_null(sym_l, sym_r);
 546
 547        return strcmp(sym_r->name, sym_l->name);
 548}
 549
 550static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf,
 551                                       size_t size, unsigned int width)
 552{
 553        return repsep_snprintf(bf, size, "%-*.*s", width, width,
 554                              he->parent ? he->parent->name : "[other]");
 555}
 556
 557struct sort_entry sort_parent = {
 558        .se_header      = "Parent symbol",
 559        .se_cmp         = sort__parent_cmp,
 560        .se_snprintf    = hist_entry__parent_snprintf,
 561        .se_width_idx   = HISTC_PARENT,
 562};
 563
 564/* --sort cpu */
 565
 566static int64_t
 567sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right)
 568{
 569        return right->cpu - left->cpu;
 570}
 571
 572static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf,
 573                                    size_t size, unsigned int width)
 574{
 575        return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu);
 576}
 577
 578struct sort_entry sort_cpu = {
 579        .se_header      = "CPU",
 580        .se_cmp         = sort__cpu_cmp,
 581        .se_snprintf    = hist_entry__cpu_snprintf,
 582        .se_width_idx   = HISTC_CPU,
 583};
 584
 585/* --sort cgroup_id */
 586
 587static int64_t _sort__cgroup_dev_cmp(u64 left_dev, u64 right_dev)
 588{
 589        return (int64_t)(right_dev - left_dev);
 590}
 591
 592static int64_t _sort__cgroup_inode_cmp(u64 left_ino, u64 right_ino)
 593{
 594        return (int64_t)(right_ino - left_ino);
 595}
 596
 597static int64_t
 598sort__cgroup_id_cmp(struct hist_entry *left, struct hist_entry *right)
 599{
 600        int64_t ret;
 601
 602        ret = _sort__cgroup_dev_cmp(right->cgroup_id.dev, left->cgroup_id.dev);
 603        if (ret != 0)
 604                return ret;
 605
 606        return _sort__cgroup_inode_cmp(right->cgroup_id.ino,
 607                                       left->cgroup_id.ino);
 608}
 609
 610static int hist_entry__cgroup_id_snprintf(struct hist_entry *he,
 611                                          char *bf, size_t size,
 612                                          unsigned int width __maybe_unused)
 613{
 614        return repsep_snprintf(bf, size, "%lu/0x%lx", he->cgroup_id.dev,
 615                               he->cgroup_id.ino);
 616}
 617
 618struct sort_entry sort_cgroup_id = {
 619        .se_header      = "cgroup id (dev/inode)",
 620        .se_cmp         = sort__cgroup_id_cmp,
 621        .se_snprintf    = hist_entry__cgroup_id_snprintf,
 622        .se_width_idx   = HISTC_CGROUP_ID,
 623};
 624
 625/* --sort socket */
 626
 627static int64_t
 628sort__socket_cmp(struct hist_entry *left, struct hist_entry *right)
 629{
 630        return right->socket - left->socket;
 631}
 632
 633static int hist_entry__socket_snprintf(struct hist_entry *he, char *bf,
 634                                    size_t size, unsigned int width)
 635{
 636        return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket);
 637}
 638
 639static int hist_entry__socket_filter(struct hist_entry *he, int type, const void *arg)
 640{
 641        int sk = *(const int *)arg;
 642
 643        if (type != HIST_FILTER__SOCKET)
 644                return -1;
 645
 646        return sk >= 0 && he->socket != sk;
 647}
 648
 649struct sort_entry sort_socket = {
 650        .se_header      = "Socket",
 651        .se_cmp         = sort__socket_cmp,
 652        .se_snprintf    = hist_entry__socket_snprintf,
 653        .se_filter      = hist_entry__socket_filter,
 654        .se_width_idx   = HISTC_SOCKET,
 655};
 656
 657/* --sort trace */
 658
 659static char *get_trace_output(struct hist_entry *he)
 660{
 661        struct trace_seq seq;
 662        struct perf_evsel *evsel;
 663        struct tep_record rec = {
 664                .data = he->raw_data,
 665                .size = he->raw_size,
 666        };
 667
 668        evsel = hists_to_evsel(he->hists);
 669
 670        trace_seq_init(&seq);
 671        if (symbol_conf.raw_trace) {
 672                tep_print_fields(&seq, he->raw_data, he->raw_size,
 673                                 evsel->tp_format);
 674        } else {
 675                tep_event_info(&seq, evsel->tp_format, &rec);
 676        }
 677        /*
 678         * Trim the buffer, it starts at 4KB and we're not going to
 679         * add anything more to this buffer.
 680         */
 681        return realloc(seq.buffer, seq.len + 1);
 682}
 683
 684static int64_t
 685sort__trace_cmp(struct hist_entry *left, struct hist_entry *right)
 686{
 687        struct perf_evsel *evsel;
 688
 689        evsel = hists_to_evsel(left->hists);
 690        if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
 691                return 0;
 692
 693        if (left->trace_output == NULL)
 694                left->trace_output = get_trace_output(left);
 695        if (right->trace_output == NULL)
 696                right->trace_output = get_trace_output(right);
 697
 698        return strcmp(right->trace_output, left->trace_output);
 699}
 700
 701static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf,
 702                                    size_t size, unsigned int width)
 703{
 704        struct perf_evsel *evsel;
 705
 706        evsel = hists_to_evsel(he->hists);
 707        if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
 708                return scnprintf(bf, size, "%-.*s", width, "N/A");
 709
 710        if (he->trace_output == NULL)
 711                he->trace_output = get_trace_output(he);
 712        return repsep_snprintf(bf, size, "%-.*s", width, he->trace_output);
 713}
 714
 715struct sort_entry sort_trace = {
 716        .se_header      = "Trace output",
 717        .se_cmp         = sort__trace_cmp,
 718        .se_snprintf    = hist_entry__trace_snprintf,
 719        .se_width_idx   = HISTC_TRACE,
 720};
 721
 722/* sort keys for branch stacks */
 723
 724static int64_t
 725sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right)
 726{
 727        if (!left->branch_info || !right->branch_info)
 728                return cmp_null(left->branch_info, right->branch_info);
 729
 730        return _sort__dso_cmp(left->branch_info->from.map,
 731                              right->branch_info->from.map);
 732}
 733
 734static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf,
 735                                    size_t size, unsigned int width)
 736{
 737        if (he->branch_info)
 738                return _hist_entry__dso_snprintf(he->branch_info->from.map,
 739                                                 bf, size, width);
 740        else
 741                return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
 742}
 743
 744static int hist_entry__dso_from_filter(struct hist_entry *he, int type,
 745                                       const void *arg)
 746{
 747        const struct dso *dso = arg;
 748
 749        if (type != HIST_FILTER__DSO)
 750                return -1;
 751
 752        return dso && (!he->branch_info || !he->branch_info->from.map ||
 753                       he->branch_info->from.map->dso != dso);
 754}
 755
 756static int64_t
 757sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right)
 758{
 759        if (!left->branch_info || !right->branch_info)
 760                return cmp_null(left->branch_info, right->branch_info);
 761
 762        return _sort__dso_cmp(left->branch_info->to.map,
 763                              right->branch_info->to.map);
 764}
 765
 766static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf,
 767                                       size_t size, unsigned int width)
 768{
 769        if (he->branch_info)
 770                return _hist_entry__dso_snprintf(he->branch_info->to.map,
 771                                                 bf, size, width);
 772        else
 773                return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
 774}
 775
 776static int hist_entry__dso_to_filter(struct hist_entry *he, int type,
 777                                     const void *arg)
 778{
 779        const struct dso *dso = arg;
 780
 781        if (type != HIST_FILTER__DSO)
 782                return -1;
 783
 784        return dso && (!he->branch_info || !he->branch_info->to.map ||
 785                       he->branch_info->to.map->dso != dso);
 786}
 787
 788static int64_t
 789sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right)
 790{
 791        struct addr_map_symbol *from_l = &left->branch_info->from;
 792        struct addr_map_symbol *from_r = &right->branch_info->from;
 793
 794        if (!left->branch_info || !right->branch_info)
 795                return cmp_null(left->branch_info, right->branch_info);
 796
 797        from_l = &left->branch_info->from;
 798        from_r = &right->branch_info->from;
 799
 800        if (!from_l->sym && !from_r->sym)
 801                return _sort__addr_cmp(from_l->addr, from_r->addr);
 802
 803        return _sort__sym_cmp(from_l->sym, from_r->sym);
 804}
 805
 806static int64_t
 807sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right)
 808{
 809        struct addr_map_symbol *to_l, *to_r;
 810
 811        if (!left->branch_info || !right->branch_info)
 812                return cmp_null(left->branch_info, right->branch_info);
 813
 814        to_l = &left->branch_info->to;
 815        to_r = &right->branch_info->to;
 816
 817        if (!to_l->sym && !to_r->sym)
 818                return _sort__addr_cmp(to_l->addr, to_r->addr);
 819
 820        return _sort__sym_cmp(to_l->sym, to_r->sym);
 821}
 822
 823static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf,
 824                                         size_t size, unsigned int width)
 825{
 826        if (he->branch_info) {
 827                struct addr_map_symbol *from = &he->branch_info->from;
 828
 829                return _hist_entry__sym_snprintf(from->map, from->sym, from->addr,
 830                                                 he->level, bf, size, width);
 831        }
 832
 833        return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
 834}
 835
 836static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf,
 837                                       size_t size, unsigned int width)
 838{
 839        if (he->branch_info) {
 840                struct addr_map_symbol *to = &he->branch_info->to;
 841
 842                return _hist_entry__sym_snprintf(to->map, to->sym, to->addr,
 843                                                 he->level, bf, size, width);
 844        }
 845
 846        return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A");
 847}
 848
 849static int hist_entry__sym_from_filter(struct hist_entry *he, int type,
 850                                       const void *arg)
 851{
 852        const char *sym = arg;
 853
 854        if (type != HIST_FILTER__SYMBOL)
 855                return -1;
 856
 857        return sym && !(he->branch_info && he->branch_info->from.sym &&
 858                        strstr(he->branch_info->from.sym->name, sym));
 859}
 860
 861static int hist_entry__sym_to_filter(struct hist_entry *he, int type,
 862                                       const void *arg)
 863{
 864        const char *sym = arg;
 865
 866        if (type != HIST_FILTER__SYMBOL)
 867                return -1;
 868
 869        return sym && !(he->branch_info && he->branch_info->to.sym &&
 870                        strstr(he->branch_info->to.sym->name, sym));
 871}
 872
 873struct sort_entry sort_dso_from = {
 874        .se_header      = "Source Shared Object",
 875        .se_cmp         = sort__dso_from_cmp,
 876        .se_snprintf    = hist_entry__dso_from_snprintf,
 877        .se_filter      = hist_entry__dso_from_filter,
 878        .se_width_idx   = HISTC_DSO_FROM,
 879};
 880
 881struct sort_entry sort_dso_to = {
 882        .se_header      = "Target Shared Object",
 883        .se_cmp         = sort__dso_to_cmp,
 884        .se_snprintf    = hist_entry__dso_to_snprintf,
 885        .se_filter      = hist_entry__dso_to_filter,
 886        .se_width_idx   = HISTC_DSO_TO,
 887};
 888
 889struct sort_entry sort_sym_from = {
 890        .se_header      = "Source Symbol",
 891        .se_cmp         = sort__sym_from_cmp,
 892        .se_snprintf    = hist_entry__sym_from_snprintf,
 893        .se_filter      = hist_entry__sym_from_filter,
 894        .se_width_idx   = HISTC_SYMBOL_FROM,
 895};
 896
 897struct sort_entry sort_sym_to = {
 898        .se_header      = "Target Symbol",
 899        .se_cmp         = sort__sym_to_cmp,
 900        .se_snprintf    = hist_entry__sym_to_snprintf,
 901        .se_filter      = hist_entry__sym_to_filter,
 902        .se_width_idx   = HISTC_SYMBOL_TO,
 903};
 904
 905static int64_t
 906sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right)
 907{
 908        unsigned char mp, p;
 909
 910        if (!left->branch_info || !right->branch_info)
 911                return cmp_null(left->branch_info, right->branch_info);
 912
 913        mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred;
 914        p  = left->branch_info->flags.predicted != right->branch_info->flags.predicted;
 915        return mp || p;
 916}
 917
 918static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf,
 919                                    size_t size, unsigned int width){
 920        static const char *out = "N/A";
 921
 922        if (he->branch_info) {
 923                if (he->branch_info->flags.predicted)
 924                        out = "N";
 925                else if (he->branch_info->flags.mispred)
 926                        out = "Y";
 927        }
 928
 929        return repsep_snprintf(bf, size, "%-*.*s", width, width, out);
 930}
 931
 932static int64_t
 933sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right)
 934{
 935        if (!left->branch_info || !right->branch_info)
 936                return cmp_null(left->branch_info, right->branch_info);
 937
 938        return left->branch_info->flags.cycles -
 939                right->branch_info->flags.cycles;
 940}
 941
 942static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf,
 943                                    size_t size, unsigned int width)
 944{
 945        if (!he->branch_info)
 946                return scnprintf(bf, size, "%-.*s", width, "N/A");
 947        if (he->branch_info->flags.cycles == 0)
 948                return repsep_snprintf(bf, size, "%-*s", width, "-");
 949        return repsep_snprintf(bf, size, "%-*hd", width,
 950                               he->branch_info->flags.cycles);
 951}
 952
 953struct sort_entry sort_cycles = {
 954        .se_header      = "Basic Block Cycles",
 955        .se_cmp         = sort__cycles_cmp,
 956        .se_snprintf    = hist_entry__cycles_snprintf,
 957        .se_width_idx   = HISTC_CYCLES,
 958};
 959
 960/* --sort daddr_sym */
 961int64_t
 962sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right)
 963{
 964        uint64_t l = 0, r = 0;
 965
 966        if (left->mem_info)
 967                l = left->mem_info->daddr.addr;
 968        if (right->mem_info)
 969                r = right->mem_info->daddr.addr;
 970
 971        return (int64_t)(r - l);
 972}
 973
 974static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf,
 975                                    size_t size, unsigned int width)
 976{
 977        uint64_t addr = 0;
 978        struct map *map = NULL;
 979        struct symbol *sym = NULL;
 980
 981        if (he->mem_info) {
 982                addr = he->mem_info->daddr.addr;
 983                map = he->mem_info->daddr.map;
 984                sym = he->mem_info->daddr.sym;
 985        }
 986        return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
 987                                         width);
 988}
 989
 990int64_t
 991sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right)
 992{
 993        uint64_t l = 0, r = 0;
 994
 995        if (left->mem_info)
 996                l = left->mem_info->iaddr.addr;
 997        if (right->mem_info)
 998                r = right->mem_info->iaddr.addr;
 999
1000        return (int64_t)(r - l);
1001}
1002
1003static int hist_entry__iaddr_snprintf(struct hist_entry *he, char *bf,
1004                                    size_t size, unsigned int width)
1005{
1006        uint64_t addr = 0;
1007        struct map *map = NULL;
1008        struct symbol *sym = NULL;
1009
1010        if (he->mem_info) {
1011                addr = he->mem_info->iaddr.addr;
1012                map  = he->mem_info->iaddr.map;
1013                sym  = he->mem_info->iaddr.sym;
1014        }
1015        return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size,
1016                                         width);
1017}
1018
1019static int64_t
1020sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
1021{
1022        struct map *map_l = NULL;
1023        struct map *map_r = NULL;
1024
1025        if (left->mem_info)
1026                map_l = left->mem_info->daddr.map;
1027        if (right->mem_info)
1028                map_r = right->mem_info->daddr.map;
1029
1030        return _sort__dso_cmp(map_l, map_r);
1031}
1032
1033static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf,
1034                                    size_t size, unsigned int width)
1035{
1036        struct map *map = NULL;
1037
1038        if (he->mem_info)
1039                map = he->mem_info->daddr.map;
1040
1041        return _hist_entry__dso_snprintf(map, bf, size, width);
1042}
1043
1044static int64_t
1045sort__locked_cmp(struct hist_entry *left, struct hist_entry *right)
1046{
1047        union perf_mem_data_src data_src_l;
1048        union perf_mem_data_src data_src_r;
1049
1050        if (left->mem_info)
1051                data_src_l = left->mem_info->data_src;
1052        else
1053                data_src_l.mem_lock = PERF_MEM_LOCK_NA;
1054
1055        if (right->mem_info)
1056                data_src_r = right->mem_info->data_src;
1057        else
1058                data_src_r.mem_lock = PERF_MEM_LOCK_NA;
1059
1060        return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock);
1061}
1062
1063static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf,
1064                                    size_t size, unsigned int width)
1065{
1066        char out[10];
1067
1068        perf_mem__lck_scnprintf(out, sizeof(out), he->mem_info);
1069        return repsep_snprintf(bf, size, "%.*s", width, out);
1070}
1071
1072static int64_t
1073sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right)
1074{
1075        union perf_mem_data_src data_src_l;
1076        union perf_mem_data_src data_src_r;
1077
1078        if (left->mem_info)
1079                data_src_l = left->mem_info->data_src;
1080        else
1081                data_src_l.mem_dtlb = PERF_MEM_TLB_NA;
1082
1083        if (right->mem_info)
1084                data_src_r = right->mem_info->data_src;
1085        else
1086                data_src_r.mem_dtlb = PERF_MEM_TLB_NA;
1087
1088        return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb);
1089}
1090
1091static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf,
1092                                    size_t size, unsigned int width)
1093{
1094        char out[64];
1095
1096        perf_mem__tlb_scnprintf(out, sizeof(out), he->mem_info);
1097        return repsep_snprintf(bf, size, "%-*s", width, out);
1098}
1099
1100static int64_t
1101sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right)
1102{
1103        union perf_mem_data_src data_src_l;
1104        union perf_mem_data_src data_src_r;
1105
1106        if (left->mem_info)
1107                data_src_l = left->mem_info->data_src;
1108        else
1109                data_src_l.mem_lvl = PERF_MEM_LVL_NA;
1110
1111        if (right->mem_info)
1112                data_src_r = right->mem_info->data_src;
1113        else
1114                data_src_r.mem_lvl = PERF_MEM_LVL_NA;
1115
1116        return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl);
1117}
1118
1119static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf,
1120                                    size_t size, unsigned int width)
1121{
1122        char out[64];
1123
1124        perf_mem__lvl_scnprintf(out, sizeof(out), he->mem_info);
1125        return repsep_snprintf(bf, size, "%-*s", width, out);
1126}
1127
1128static int64_t
1129sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right)
1130{
1131        union perf_mem_data_src data_src_l;
1132        union perf_mem_data_src data_src_r;
1133
1134        if (left->mem_info)
1135                data_src_l = left->mem_info->data_src;
1136        else
1137                data_src_l.mem_snoop = PERF_MEM_SNOOP_NA;
1138
1139        if (right->mem_info)
1140                data_src_r = right->mem_info->data_src;
1141        else
1142                data_src_r.mem_snoop = PERF_MEM_SNOOP_NA;
1143
1144        return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop);
1145}
1146
1147static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf,
1148                                    size_t size, unsigned int width)
1149{
1150        char out[64];
1151
1152        perf_mem__snp_scnprintf(out, sizeof(out), he->mem_info);
1153        return repsep_snprintf(bf, size, "%-*s", width, out);
1154}
1155
1156int64_t
1157sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right)
1158{
1159        u64 l, r;
1160        struct map *l_map, *r_map;
1161
1162        if (!left->mem_info)  return -1;
1163        if (!right->mem_info) return 1;
1164
1165        /* group event types together */
1166        if (left->cpumode > right->cpumode) return -1;
1167        if (left->cpumode < right->cpumode) return 1;
1168
1169        l_map = left->mem_info->daddr.map;
1170        r_map = right->mem_info->daddr.map;
1171
1172        /* if both are NULL, jump to sort on al_addr instead */
1173        if (!l_map && !r_map)
1174                goto addr;
1175
1176        if (!l_map) return -1;
1177        if (!r_map) return 1;
1178
1179        if (l_map->maj > r_map->maj) return -1;
1180        if (l_map->maj < r_map->maj) return 1;
1181
1182        if (l_map->min > r_map->min) return -1;
1183        if (l_map->min < r_map->min) return 1;
1184
1185        if (l_map->ino > r_map->ino) return -1;
1186        if (l_map->ino < r_map->ino) return 1;
1187
1188        if (l_map->ino_generation > r_map->ino_generation) return -1;
1189        if (l_map->ino_generation < r_map->ino_generation) return 1;
1190
1191        /*
1192         * Addresses with no major/minor numbers are assumed to be
1193         * anonymous in userspace.  Sort those on pid then address.
1194         *
1195         * The kernel and non-zero major/minor mapped areas are
1196         * assumed to be unity mapped.  Sort those on address.
1197         */
1198
1199        if ((left->cpumode != PERF_RECORD_MISC_KERNEL) &&
1200            (!(l_map->flags & MAP_SHARED)) &&
1201            !l_map->maj && !l_map->min && !l_map->ino &&
1202            !l_map->ino_generation) {
1203                /* userspace anonymous */
1204
1205                if (left->thread->pid_ > right->thread->pid_) return -1;
1206                if (left->thread->pid_ < right->thread->pid_) return 1;
1207        }
1208
1209addr:
1210        /* al_addr does all the right addr - start + offset calculations */
1211        l = cl_address(left->mem_info->daddr.al_addr);
1212        r = cl_address(right->mem_info->daddr.al_addr);
1213
1214        if (l > r) return -1;
1215        if (l < r) return 1;
1216
1217        return 0;
1218}
1219
1220static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf,
1221                                          size_t size, unsigned int width)
1222{
1223
1224        uint64_t addr = 0;
1225        struct map *map = NULL;
1226        struct symbol *sym = NULL;
1227        char level = he->level;
1228
1229        if (he->mem_info) {
1230                addr = cl_address(he->mem_info->daddr.al_addr);
1231                map = he->mem_info->daddr.map;
1232                sym = he->mem_info->daddr.sym;
1233
1234                /* print [s] for shared data mmaps */
1235                if ((he->cpumode != PERF_RECORD_MISC_KERNEL) &&
1236                     map && !(map->prot & PROT_EXEC) &&
1237                    (map->flags & MAP_SHARED) &&
1238                    (map->maj || map->min || map->ino ||
1239                     map->ino_generation))
1240                        level = 's';
1241                else if (!map)
1242                        level = 'X';
1243        }
1244        return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size,
1245                                         width);
1246}
1247
1248struct sort_entry sort_mispredict = {
1249        .se_header      = "Branch Mispredicted",
1250        .se_cmp         = sort__mispredict_cmp,
1251        .se_snprintf    = hist_entry__mispredict_snprintf,
1252        .se_width_idx   = HISTC_MISPREDICT,
1253};
1254
1255static u64 he_weight(struct hist_entry *he)
1256{
1257        return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0;
1258}
1259
1260static int64_t
1261sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1262{
1263        return he_weight(left) - he_weight(right);
1264}
1265
1266static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf,
1267                                    size_t size, unsigned int width)
1268{
1269        return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he));
1270}
1271
1272struct sort_entry sort_local_weight = {
1273        .se_header      = "Local Weight",
1274        .se_cmp         = sort__local_weight_cmp,
1275        .se_snprintf    = hist_entry__local_weight_snprintf,
1276        .se_width_idx   = HISTC_LOCAL_WEIGHT,
1277};
1278
1279static int64_t
1280sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right)
1281{
1282        return left->stat.weight - right->stat.weight;
1283}
1284
1285static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf,
1286                                              size_t size, unsigned int width)
1287{
1288        return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight);
1289}
1290
1291struct sort_entry sort_global_weight = {
1292        .se_header      = "Weight",
1293        .se_cmp         = sort__global_weight_cmp,
1294        .se_snprintf    = hist_entry__global_weight_snprintf,
1295        .se_width_idx   = HISTC_GLOBAL_WEIGHT,
1296};
1297
1298struct sort_entry sort_mem_daddr_sym = {
1299        .se_header      = "Data Symbol",
1300        .se_cmp         = sort__daddr_cmp,
1301        .se_snprintf    = hist_entry__daddr_snprintf,
1302        .se_width_idx   = HISTC_MEM_DADDR_SYMBOL,
1303};
1304
1305struct sort_entry sort_mem_iaddr_sym = {
1306        .se_header      = "Code Symbol",
1307        .se_cmp         = sort__iaddr_cmp,
1308        .se_snprintf    = hist_entry__iaddr_snprintf,
1309        .se_width_idx   = HISTC_MEM_IADDR_SYMBOL,
1310};
1311
1312struct sort_entry sort_mem_daddr_dso = {
1313        .se_header      = "Data Object",
1314        .se_cmp         = sort__dso_daddr_cmp,
1315        .se_snprintf    = hist_entry__dso_daddr_snprintf,
1316        .se_width_idx   = HISTC_MEM_DADDR_DSO,
1317};
1318
1319struct sort_entry sort_mem_locked = {
1320        .se_header      = "Locked",
1321        .se_cmp         = sort__locked_cmp,
1322        .se_snprintf    = hist_entry__locked_snprintf,
1323        .se_width_idx   = HISTC_MEM_LOCKED,
1324};
1325
1326struct sort_entry sort_mem_tlb = {
1327        .se_header      = "TLB access",
1328        .se_cmp         = sort__tlb_cmp,
1329        .se_snprintf    = hist_entry__tlb_snprintf,
1330        .se_width_idx   = HISTC_MEM_TLB,
1331};
1332
1333struct sort_entry sort_mem_lvl = {
1334        .se_header      = "Memory access",
1335        .se_cmp         = sort__lvl_cmp,
1336        .se_snprintf    = hist_entry__lvl_snprintf,
1337        .se_width_idx   = HISTC_MEM_LVL,
1338};
1339
1340struct sort_entry sort_mem_snoop = {
1341        .se_header      = "Snoop",
1342        .se_cmp         = sort__snoop_cmp,
1343        .se_snprintf    = hist_entry__snoop_snprintf,
1344        .se_width_idx   = HISTC_MEM_SNOOP,
1345};
1346
1347struct sort_entry sort_mem_dcacheline = {
1348        .se_header      = "Data Cacheline",
1349        .se_cmp         = sort__dcacheline_cmp,
1350        .se_snprintf    = hist_entry__dcacheline_snprintf,
1351        .se_width_idx   = HISTC_MEM_DCACHELINE,
1352};
1353
1354static int64_t
1355sort__phys_daddr_cmp(struct hist_entry *left, struct hist_entry *right)
1356{
1357        uint64_t l = 0, r = 0;
1358
1359        if (left->mem_info)
1360                l = left->mem_info->daddr.phys_addr;
1361        if (right->mem_info)
1362                r = right->mem_info->daddr.phys_addr;
1363
1364        return (int64_t)(r - l);
1365}
1366
1367static int hist_entry__phys_daddr_snprintf(struct hist_entry *he, char *bf,
1368                                           size_t size, unsigned int width)
1369{
1370        uint64_t addr = 0;
1371        size_t ret = 0;
1372        size_t len = BITS_PER_LONG / 4;
1373
1374        addr = he->mem_info->daddr.phys_addr;
1375
1376        ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", he->level);
1377
1378        ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", len, addr);
1379
1380        ret += repsep_snprintf(bf + ret, size - ret, "%-*s", width - ret, "");
1381
1382        if (ret > width)
1383                bf[width] = '\0';
1384
1385        return width;
1386}
1387
1388struct sort_entry sort_mem_phys_daddr = {
1389        .se_header      = "Data Physical Address",
1390        .se_cmp         = sort__phys_daddr_cmp,
1391        .se_snprintf    = hist_entry__phys_daddr_snprintf,
1392        .se_width_idx   = HISTC_MEM_PHYS_DADDR,
1393};
1394
1395static int64_t
1396sort__abort_cmp(struct hist_entry *left, struct hist_entry *right)
1397{
1398        if (!left->branch_info || !right->branch_info)
1399                return cmp_null(left->branch_info, right->branch_info);
1400
1401        return left->branch_info->flags.abort !=
1402                right->branch_info->flags.abort;
1403}
1404
1405static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf,
1406                                    size_t size, unsigned int width)
1407{
1408        static const char *out = "N/A";
1409
1410        if (he->branch_info) {
1411                if (he->branch_info->flags.abort)
1412                        out = "A";
1413                else
1414                        out = ".";
1415        }
1416
1417        return repsep_snprintf(bf, size, "%-*s", width, out);
1418}
1419
1420struct sort_entry sort_abort = {
1421        .se_header      = "Transaction abort",
1422        .se_cmp         = sort__abort_cmp,
1423        .se_snprintf    = hist_entry__abort_snprintf,
1424        .se_width_idx   = HISTC_ABORT,
1425};
1426
1427static int64_t
1428sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right)
1429{
1430        if (!left->branch_info || !right->branch_info)
1431                return cmp_null(left->branch_info, right->branch_info);
1432
1433        return left->branch_info->flags.in_tx !=
1434                right->branch_info->flags.in_tx;
1435}
1436
1437static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf,
1438                                    size_t size, unsigned int width)
1439{
1440        static const char *out = "N/A";
1441
1442        if (he->branch_info) {
1443                if (he->branch_info->flags.in_tx)
1444                        out = "T";
1445                else
1446                        out = ".";
1447        }
1448
1449        return repsep_snprintf(bf, size, "%-*s", width, out);
1450}
1451
1452struct sort_entry sort_in_tx = {
1453        .se_header      = "Branch in transaction",
1454        .se_cmp         = sort__in_tx_cmp,
1455        .se_snprintf    = hist_entry__in_tx_snprintf,
1456        .se_width_idx   = HISTC_IN_TX,
1457};
1458
1459static int64_t
1460sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right)
1461{
1462        return left->transaction - right->transaction;
1463}
1464
1465static inline char *add_str(char *p, const char *str)
1466{
1467        strcpy(p, str);
1468        return p + strlen(str);
1469}
1470
1471static struct txbit {
1472        unsigned flag;
1473        const char *name;
1474        int skip_for_len;
1475} txbits[] = {
1476        { PERF_TXN_ELISION,        "EL ",        0 },
1477        { PERF_TXN_TRANSACTION,    "TX ",        1 },
1478        { PERF_TXN_SYNC,           "SYNC ",      1 },
1479        { PERF_TXN_ASYNC,          "ASYNC ",     0 },
1480        { PERF_TXN_RETRY,          "RETRY ",     0 },
1481        { PERF_TXN_CONFLICT,       "CON ",       0 },
1482        { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 },
1483        { PERF_TXN_CAPACITY_READ,  "CAP-READ ",  0 },
1484        { 0, NULL, 0 }
1485};
1486
1487int hist_entry__transaction_len(void)
1488{
1489        int i;
1490        int len = 0;
1491
1492        for (i = 0; txbits[i].name; i++) {
1493                if (!txbits[i].skip_for_len)
1494                        len += strlen(txbits[i].name);
1495        }
1496        len += 4; /* :XX<space> */
1497        return len;
1498}
1499
1500static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf,
1501                                            size_t size, unsigned int width)
1502{
1503        u64 t = he->transaction;
1504        char buf[128];
1505        char *p = buf;
1506        int i;
1507
1508        buf[0] = 0;
1509        for (i = 0; txbits[i].name; i++)
1510                if (txbits[i].flag & t)
1511                        p = add_str(p, txbits[i].name);
1512        if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC)))
1513                p = add_str(p, "NEITHER ");
1514        if (t & PERF_TXN_ABORT_MASK) {
1515                sprintf(p, ":%" PRIx64,
1516                        (t & PERF_TXN_ABORT_MASK) >>
1517                        PERF_TXN_ABORT_SHIFT);
1518                p += strlen(p);
1519        }
1520
1521        return repsep_snprintf(bf, size, "%-*s", width, buf);
1522}
1523
1524struct sort_entry sort_transaction = {
1525        .se_header      = "Transaction                ",
1526        .se_cmp         = sort__transaction_cmp,
1527        .se_snprintf    = hist_entry__transaction_snprintf,
1528        .se_width_idx   = HISTC_TRANSACTION,
1529};
1530
1531/* --sort symbol_size */
1532
1533static int64_t _sort__sym_size_cmp(struct symbol *sym_l, struct symbol *sym_r)
1534{
1535        int64_t size_l = sym_l != NULL ? symbol__size(sym_l) : 0;
1536        int64_t size_r = sym_r != NULL ? symbol__size(sym_r) : 0;
1537
1538        return size_l < size_r ? -1 :
1539                size_l == size_r ? 0 : 1;
1540}
1541
1542static int64_t
1543sort__sym_size_cmp(struct hist_entry *left, struct hist_entry *right)
1544{
1545        return _sort__sym_size_cmp(right->ms.sym, left->ms.sym);
1546}
1547
1548static int _hist_entry__sym_size_snprintf(struct symbol *sym, char *bf,
1549                                          size_t bf_size, unsigned int width)
1550{
1551        if (sym)
1552                return repsep_snprintf(bf, bf_size, "%*d", width, symbol__size(sym));
1553
1554        return repsep_snprintf(bf, bf_size, "%*s", width, "unknown");
1555}
1556
1557static int hist_entry__sym_size_snprintf(struct hist_entry *he, char *bf,
1558                                         size_t size, unsigned int width)
1559{
1560        return _hist_entry__sym_size_snprintf(he->ms.sym, bf, size, width);
1561}
1562
1563struct sort_entry sort_sym_size = {
1564        .se_header      = "Symbol size",
1565        .se_cmp         = sort__sym_size_cmp,
1566        .se_snprintf    = hist_entry__sym_size_snprintf,
1567        .se_width_idx   = HISTC_SYM_SIZE,
1568};
1569
1570/* --sort dso_size */
1571
1572static int64_t _sort__dso_size_cmp(struct map *map_l, struct map *map_r)
1573{
1574        int64_t size_l = map_l != NULL ? map__size(map_l) : 0;
1575        int64_t size_r = map_r != NULL ? map__size(map_r) : 0;
1576
1577        return size_l < size_r ? -1 :
1578                size_l == size_r ? 0 : 1;
1579}
1580
1581static int64_t
1582sort__dso_size_cmp(struct hist_entry *left, struct hist_entry *right)
1583{
1584        return _sort__dso_size_cmp(right->ms.map, left->ms.map);
1585}
1586
1587static int _hist_entry__dso_size_snprintf(struct map *map, char *bf,
1588                                          size_t bf_size, unsigned int width)
1589{
1590        if (map && map->dso)
1591                return repsep_snprintf(bf, bf_size, "%*d", width,
1592                                       map__size(map));
1593
1594        return repsep_snprintf(bf, bf_size, "%*s", width, "unknown");
1595}
1596
1597static int hist_entry__dso_size_snprintf(struct hist_entry *he, char *bf,
1598                                         size_t size, unsigned int width)
1599{
1600        return _hist_entry__dso_size_snprintf(he->ms.map, bf, size, width);
1601}
1602
1603struct sort_entry sort_dso_size = {
1604        .se_header      = "DSO size",
1605        .se_cmp         = sort__dso_size_cmp,
1606        .se_snprintf    = hist_entry__dso_size_snprintf,
1607        .se_width_idx   = HISTC_DSO_SIZE,
1608};
1609
1610
1611struct sort_dimension {
1612        const char              *name;
1613        struct sort_entry       *entry;
1614        int                     taken;
1615};
1616
1617#define DIM(d, n, func) [d] = { .name = n, .entry = &(func) }
1618
1619static struct sort_dimension common_sort_dimensions[] = {
1620        DIM(SORT_PID, "pid", sort_thread),
1621        DIM(SORT_COMM, "comm", sort_comm),
1622        DIM(SORT_DSO, "dso", sort_dso),
1623        DIM(SORT_SYM, "symbol", sort_sym),
1624        DIM(SORT_PARENT, "parent", sort_parent),
1625        DIM(SORT_CPU, "cpu", sort_cpu),
1626        DIM(SORT_SOCKET, "socket", sort_socket),
1627        DIM(SORT_SRCLINE, "srcline", sort_srcline),
1628        DIM(SORT_SRCFILE, "srcfile", sort_srcfile),
1629        DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight),
1630        DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight),
1631        DIM(SORT_TRANSACTION, "transaction", sort_transaction),
1632        DIM(SORT_TRACE, "trace", sort_trace),
1633        DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size),
1634        DIM(SORT_DSO_SIZE, "dso_size", sort_dso_size),
1635        DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id),
1636        DIM(SORT_SYM_IPC_NULL, "ipc_null", sort_sym_ipc_null),
1637};
1638
1639#undef DIM
1640
1641#define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) }
1642
1643static struct sort_dimension bstack_sort_dimensions[] = {
1644        DIM(SORT_DSO_FROM, "dso_from", sort_dso_from),
1645        DIM(SORT_DSO_TO, "dso_to", sort_dso_to),
1646        DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from),
1647        DIM(SORT_SYM_TO, "symbol_to", sort_sym_to),
1648        DIM(SORT_MISPREDICT, "mispredict", sort_mispredict),
1649        DIM(SORT_IN_TX, "in_tx", sort_in_tx),
1650        DIM(SORT_ABORT, "abort", sort_abort),
1651        DIM(SORT_CYCLES, "cycles", sort_cycles),
1652        DIM(SORT_SRCLINE_FROM, "srcline_from", sort_srcline_from),
1653        DIM(SORT_SRCLINE_TO, "srcline_to", sort_srcline_to),
1654        DIM(SORT_SYM_IPC, "ipc_lbr", sort_sym_ipc),
1655};
1656
1657#undef DIM
1658
1659#define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) }
1660
1661static struct sort_dimension memory_sort_dimensions[] = {
1662        DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym),
1663        DIM(SORT_MEM_IADDR_SYMBOL, "symbol_iaddr", sort_mem_iaddr_sym),
1664        DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso),
1665        DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked),
1666        DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb),
1667        DIM(SORT_MEM_LVL, "mem", sort_mem_lvl),
1668        DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop),
1669        DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline),
1670        DIM(SORT_MEM_PHYS_DADDR, "phys_daddr", sort_mem_phys_daddr),
1671};
1672
1673#undef DIM
1674
1675struct hpp_dimension {
1676        const char              *name;
1677        struct perf_hpp_fmt     *fmt;
1678        int                     taken;
1679};
1680
1681#define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], }
1682
1683static struct hpp_dimension hpp_sort_dimensions[] = {
1684        DIM(PERF_HPP__OVERHEAD, "overhead"),
1685        DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"),
1686        DIM(PERF_HPP__OVERHEAD_US, "overhead_us"),
1687        DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"),
1688        DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"),
1689        DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"),
1690        DIM(PERF_HPP__SAMPLES, "sample"),
1691        DIM(PERF_HPP__PERIOD, "period"),
1692};
1693
1694#undef DIM
1695
1696struct hpp_sort_entry {
1697        struct perf_hpp_fmt hpp;
1698        struct sort_entry *se;
1699};
1700
1701void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
1702{
1703        struct hpp_sort_entry *hse;
1704
1705        if (!perf_hpp__is_sort_entry(fmt))
1706                return;
1707
1708        hse = container_of(fmt, struct hpp_sort_entry, hpp);
1709        hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name));
1710}
1711
1712static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1713                              struct hists *hists, int line __maybe_unused,
1714                              int *span __maybe_unused)
1715{
1716        struct hpp_sort_entry *hse;
1717        size_t len = fmt->user_len;
1718
1719        hse = container_of(fmt, struct hpp_sort_entry, hpp);
1720
1721        if (!len)
1722                len = hists__col_len(hists, hse->se->se_width_idx);
1723
1724        return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name);
1725}
1726
1727static int __sort__hpp_width(struct perf_hpp_fmt *fmt,
1728                             struct perf_hpp *hpp __maybe_unused,
1729                             struct hists *hists)
1730{
1731        struct hpp_sort_entry *hse;
1732        size_t len = fmt->user_len;
1733
1734        hse = container_of(fmt, struct hpp_sort_entry, hpp);
1735
1736        if (!len)
1737                len = hists__col_len(hists, hse->se->se_width_idx);
1738
1739        return len;
1740}
1741
1742static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
1743                             struct hist_entry *he)
1744{
1745        struct hpp_sort_entry *hse;
1746        size_t len = fmt->user_len;
1747
1748        hse = container_of(fmt, struct hpp_sort_entry, hpp);
1749
1750        if (!len)
1751                len = hists__col_len(he->hists, hse->se->se_width_idx);
1752
1753        return hse->se->se_snprintf(he, hpp->buf, hpp->size, len);
1754}
1755
1756static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt,
1757                               struct hist_entry *a, struct hist_entry *b)
1758{
1759        struct hpp_sort_entry *hse;
1760
1761        hse = container_of(fmt, struct hpp_sort_entry, hpp);
1762        return hse->se->se_cmp(a, b);
1763}
1764
1765static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt,
1766                                    struct hist_entry *a, struct hist_entry *b)
1767{
1768        struct hpp_sort_entry *hse;
1769        int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *);
1770
1771        hse = container_of(fmt, struct hpp_sort_entry, hpp);
1772        collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp;
1773        return collapse_fn(a, b);
1774}
1775
1776static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
1777                                struct hist_entry *a, struct hist_entry *b)
1778{
1779        struct hpp_sort_entry *hse;
1780        int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *);
1781
1782        hse = container_of(fmt, struct hpp_sort_entry, hpp);
1783        sort_fn = hse->se->se_sort ?: hse->se->se_cmp;
1784        return sort_fn(a, b);
1785}
1786
1787bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
1788{
1789        return format->header == __sort__hpp_header;
1790}
1791
1792#define MK_SORT_ENTRY_CHK(key)                                  \
1793bool perf_hpp__is_ ## key ## _entry(struct perf_hpp_fmt *fmt)   \
1794{                                                               \
1795        struct hpp_sort_entry *hse;                             \
1796                                                                \
1797        if (!perf_hpp__is_sort_entry(fmt))                      \
1798                return false;                                   \
1799                                                                \
1800        hse = container_of(fmt, struct hpp_sort_entry, hpp);    \
1801        return hse->se == &sort_ ## key ;                       \
1802}
1803
1804MK_SORT_ENTRY_CHK(trace)
1805MK_SORT_ENTRY_CHK(srcline)
1806MK_SORT_ENTRY_CHK(srcfile)
1807MK_SORT_ENTRY_CHK(thread)
1808MK_SORT_ENTRY_CHK(comm)
1809MK_SORT_ENTRY_CHK(dso)
1810MK_SORT_ENTRY_CHK(sym)
1811
1812
1813static bool __sort__hpp_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
1814{
1815        struct hpp_sort_entry *hse_a;
1816        struct hpp_sort_entry *hse_b;
1817
1818        if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
1819                return false;
1820
1821        hse_a = container_of(a, struct hpp_sort_entry, hpp);
1822        hse_b = container_of(b, struct hpp_sort_entry, hpp);
1823
1824        return hse_a->se == hse_b->se;
1825}
1826
1827static void hse_free(struct perf_hpp_fmt *fmt)
1828{
1829        struct hpp_sort_entry *hse;
1830
1831        hse = container_of(fmt, struct hpp_sort_entry, hpp);
1832        free(hse);
1833}
1834
1835static struct hpp_sort_entry *
1836__sort_dimension__alloc_hpp(struct sort_dimension *sd, int level)
1837{
1838        struct hpp_sort_entry *hse;
1839
1840        hse = malloc(sizeof(*hse));
1841        if (hse == NULL) {
1842                pr_err("Memory allocation failed\n");
1843                return NULL;
1844        }
1845
1846        hse->se = sd->entry;
1847        hse->hpp.name = sd->entry->se_header;
1848        hse->hpp.header = __sort__hpp_header;
1849        hse->hpp.width = __sort__hpp_width;
1850        hse->hpp.entry = __sort__hpp_entry;
1851        hse->hpp.color = NULL;
1852
1853        hse->hpp.cmp = __sort__hpp_cmp;
1854        hse->hpp.collapse = __sort__hpp_collapse;
1855        hse->hpp.sort = __sort__hpp_sort;
1856        hse->hpp.equal = __sort__hpp_equal;
1857        hse->hpp.free = hse_free;
1858
1859        INIT_LIST_HEAD(&hse->hpp.list);
1860        INIT_LIST_HEAD(&hse->hpp.sort_list);
1861        hse->hpp.elide = false;
1862        hse->hpp.len = 0;
1863        hse->hpp.user_len = 0;
1864        hse->hpp.level = level;
1865
1866        return hse;
1867}
1868
1869static void hpp_free(struct perf_hpp_fmt *fmt)
1870{
1871        free(fmt);
1872}
1873
1874static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd,
1875                                                       int level)
1876{
1877        struct perf_hpp_fmt *fmt;
1878
1879        fmt = memdup(hd->fmt, sizeof(*fmt));
1880        if (fmt) {
1881                INIT_LIST_HEAD(&fmt->list);
1882                INIT_LIST_HEAD(&fmt->sort_list);
1883                fmt->free = hpp_free;
1884                fmt->level = level;
1885        }
1886
1887        return fmt;
1888}
1889
1890int hist_entry__filter(struct hist_entry *he, int type, const void *arg)
1891{
1892        struct perf_hpp_fmt *fmt;
1893        struct hpp_sort_entry *hse;
1894        int ret = -1;
1895        int r;
1896
1897        perf_hpp_list__for_each_format(he->hpp_list, fmt) {
1898                if (!perf_hpp__is_sort_entry(fmt))
1899                        continue;
1900
1901                hse = container_of(fmt, struct hpp_sort_entry, hpp);
1902                if (hse->se->se_filter == NULL)
1903                        continue;
1904
1905                /*
1906                 * hist entry is filtered if any of sort key in the hpp list
1907                 * is applied.  But it should skip non-matched filter types.
1908                 */
1909                r = hse->se->se_filter(he, type, arg);
1910                if (r >= 0) {
1911                        if (ret < 0)
1912                                ret = 0;
1913                        ret |= r;
1914                }
1915        }
1916
1917        return ret;
1918}
1919
1920static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd,
1921                                          struct perf_hpp_list *list,
1922                                          int level)
1923{
1924        struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, level);
1925
1926        if (hse == NULL)
1927                return -1;
1928
1929        perf_hpp_list__register_sort_field(list, &hse->hpp);
1930        return 0;
1931}
1932
1933static int __sort_dimension__add_hpp_output(struct sort_dimension *sd,
1934                                            struct perf_hpp_list *list)
1935{
1936        struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, 0);
1937
1938        if (hse == NULL)
1939                return -1;
1940
1941        perf_hpp_list__column_register(list, &hse->hpp);
1942        return 0;
1943}
1944
1945struct hpp_dynamic_entry {
1946        struct perf_hpp_fmt hpp;
1947        struct perf_evsel *evsel;
1948        struct tep_format_field *field;
1949        unsigned dynamic_len;
1950        bool raw_trace;
1951};
1952
1953static int hde_width(struct hpp_dynamic_entry *hde)
1954{
1955        if (!hde->hpp.len) {
1956                int len = hde->dynamic_len;
1957                int namelen = strlen(hde->field->name);
1958                int fieldlen = hde->field->size;
1959
1960                if (namelen > len)
1961                        len = namelen;
1962
1963                if (!(hde->field->flags & TEP_FIELD_IS_STRING)) {
1964                        /* length for print hex numbers */
1965                        fieldlen = hde->field->size * 2 + 2;
1966                }
1967                if (fieldlen > len)
1968                        len = fieldlen;
1969
1970                hde->hpp.len = len;
1971        }
1972        return hde->hpp.len;
1973}
1974
1975static void update_dynamic_len(struct hpp_dynamic_entry *hde,
1976                               struct hist_entry *he)
1977{
1978        char *str, *pos;
1979        struct tep_format_field *field = hde->field;
1980        size_t namelen;
1981        bool last = false;
1982
1983        if (hde->raw_trace)
1984                return;
1985
1986        /* parse pretty print result and update max length */
1987        if (!he->trace_output)
1988                he->trace_output = get_trace_output(he);
1989
1990        namelen = strlen(field->name);
1991        str = he->trace_output;
1992
1993        while (str) {
1994                pos = strchr(str, ' ');
1995                if (pos == NULL) {
1996                        last = true;
1997                        pos = str + strlen(str);
1998                }
1999
2000                if (!strncmp(str, field->name, namelen)) {
2001                        size_t len;
2002
2003                        str += namelen + 1;
2004                        len = pos - str;
2005
2006                        if (len > hde->dynamic_len)
2007                                hde->dynamic_len = len;
2008                        break;
2009                }
2010
2011                if (last)
2012                        str = NULL;
2013                else
2014                        str = pos + 1;
2015        }
2016}
2017
2018static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
2019                              struct hists *hists __maybe_unused,
2020                              int line __maybe_unused,
2021                              int *span __maybe_unused)
2022{
2023        struct hpp_dynamic_entry *hde;
2024        size_t len = fmt->user_len;
2025
2026        hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
2027
2028        if (!len)
2029                len = hde_width(hde);
2030
2031        return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name);
2032}
2033
2034static int __sort__hde_width(struct perf_hpp_fmt *fmt,
2035                             struct perf_hpp *hpp __maybe_unused,
2036                             struct hists *hists __maybe_unused)
2037{
2038        struct hpp_dynamic_entry *hde;
2039        size_t len = fmt->user_len;
2040
2041        hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
2042
2043        if (!len)
2044                len = hde_width(hde);
2045
2046        return len;
2047}
2048
2049bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists)
2050{
2051        struct hpp_dynamic_entry *hde;
2052
2053        hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
2054
2055        return hists_to_evsel(hists) == hde->evsel;
2056}
2057
2058static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
2059                             struct hist_entry *he)
2060{
2061        struct hpp_dynamic_entry *hde;
2062        size_t len = fmt->user_len;
2063        char *str, *pos;
2064        struct tep_format_field *field;
2065        size_t namelen;
2066        bool last = false;
2067        int ret;
2068
2069        hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
2070
2071        if (!len)
2072                len = hde_width(hde);
2073
2074        if (hde->raw_trace)
2075                goto raw_field;
2076
2077        if (!he->trace_output)
2078                he->trace_output = get_trace_output(he);
2079
2080        field = hde->field;
2081        namelen = strlen(field->name);
2082        str = he->trace_output;
2083
2084        while (str) {
2085                pos = strchr(str, ' ');
2086                if (pos == NULL) {
2087                        last = true;
2088                        pos = str + strlen(str);
2089                }
2090
2091                if (!strncmp(str, field->name, namelen)) {
2092                        str += namelen + 1;
2093                        str = strndup(str, pos - str);
2094
2095                        if (str == NULL)
2096                                return scnprintf(hpp->buf, hpp->size,
2097                                                 "%*.*s", len, len, "ERROR");
2098                        break;
2099                }
2100
2101                if (last)
2102                        str = NULL;
2103                else
2104                        str = pos + 1;
2105        }
2106
2107        if (str == NULL) {
2108                struct trace_seq seq;
2109raw_field:
2110                trace_seq_init(&seq);
2111                tep_print_field(&seq, he->raw_data, hde->field);
2112                str = seq.buffer;
2113        }
2114
2115        ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str);
2116        free(str);
2117        return ret;
2118}
2119
2120static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
2121                               struct hist_entry *a, struct hist_entry *b)
2122{
2123        struct hpp_dynamic_entry *hde;
2124        struct tep_format_field *field;
2125        unsigned offset, size;
2126
2127        hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
2128
2129        if (b == NULL) {
2130                update_dynamic_len(hde, a);
2131                return 0;
2132        }
2133
2134        field = hde->field;
2135        if (field->flags & TEP_FIELD_IS_DYNAMIC) {
2136                unsigned long long dyn;
2137
2138                tep_read_number_field(field, a->raw_data, &dyn);
2139                offset = dyn & 0xffff;
2140                size = (dyn >> 16) & 0xffff;
2141
2142                /* record max width for output */
2143                if (size > hde->dynamic_len)
2144                        hde->dynamic_len = size;
2145        } else {
2146                offset = field->offset;
2147                size = field->size;
2148        }
2149
2150        return memcmp(a->raw_data + offset, b->raw_data + offset, size);
2151}
2152
2153bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
2154{
2155        return fmt->cmp == __sort__hde_cmp;
2156}
2157
2158static bool __sort__hde_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
2159{
2160        struct hpp_dynamic_entry *hde_a;
2161        struct hpp_dynamic_entry *hde_b;
2162
2163        if (!perf_hpp__is_dynamic_entry(a) || !perf_hpp__is_dynamic_entry(b))
2164                return false;
2165
2166        hde_a = container_of(a, struct hpp_dynamic_entry, hpp);
2167        hde_b = container_of(b, struct hpp_dynamic_entry, hpp);
2168
2169        return hde_a->field == hde_b->field;
2170}
2171
2172static void hde_free(struct perf_hpp_fmt *fmt)
2173{
2174        struct hpp_dynamic_entry *hde;
2175
2176        hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
2177        free(hde);
2178}
2179
2180static struct hpp_dynamic_entry *
2181__alloc_dynamic_entry(struct perf_evsel *evsel, struct tep_format_field *field,
2182                      int level)
2183{
2184        struct hpp_dynamic_entry *hde;
2185
2186        hde = malloc(sizeof(*hde));
2187        if (hde == NULL) {
2188                pr_debug("Memory allocation failed\n");
2189                return NULL;
2190        }
2191
2192        hde->evsel = evsel;
2193        hde->field = field;
2194        hde->dynamic_len = 0;
2195
2196        hde->hpp.name = field->name;
2197        hde->hpp.header = __sort__hde_header;
2198        hde->hpp.width  = __sort__hde_width;
2199        hde->hpp.entry  = __sort__hde_entry;
2200        hde->hpp.color  = NULL;
2201
2202        hde->hpp.cmp = __sort__hde_cmp;
2203        hde->hpp.collapse = __sort__hde_cmp;
2204        hde->hpp.sort = __sort__hde_cmp;
2205        hde->hpp.equal = __sort__hde_equal;
2206        hde->hpp.free = hde_free;
2207
2208        INIT_LIST_HEAD(&hde->hpp.list);
2209        INIT_LIST_HEAD(&hde->hpp.sort_list);
2210        hde->hpp.elide = false;
2211        hde->hpp.len = 0;
2212        hde->hpp.user_len = 0;
2213        hde->hpp.level = level;
2214
2215        return hde;
2216}
2217
2218struct perf_hpp_fmt *perf_hpp_fmt__dup(struct perf_hpp_fmt *fmt)
2219{
2220        struct perf_hpp_fmt *new_fmt = NULL;
2221
2222        if (perf_hpp__is_sort_entry(fmt)) {
2223                struct hpp_sort_entry *hse, *new_hse;
2224
2225                hse = container_of(fmt, struct hpp_sort_entry, hpp);
2226                new_hse = memdup(hse, sizeof(*hse));
2227                if (new_hse)
2228                        new_fmt = &new_hse->hpp;
2229        } else if (perf_hpp__is_dynamic_entry(fmt)) {
2230                struct hpp_dynamic_entry *hde, *new_hde;
2231
2232                hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
2233                new_hde = memdup(hde, sizeof(*hde));
2234                if (new_hde)
2235                        new_fmt = &new_hde->hpp;
2236        } else {
2237                new_fmt = memdup(fmt, sizeof(*fmt));
2238        }
2239
2240        INIT_LIST_HEAD(&new_fmt->list);
2241        INIT_LIST_HEAD(&new_fmt->sort_list);
2242
2243        return new_fmt;
2244}
2245
2246static int parse_field_name(char *str, char **event, char **field, char **opt)
2247{
2248        char *event_name, *field_name, *opt_name;
2249
2250        event_name = str;
2251        field_name = strchr(str, '.');
2252
2253        if (field_name) {
2254                *field_name++ = '\0';
2255        } else {
2256                event_name = NULL;
2257                field_name = str;
2258        }
2259
2260        opt_name = strchr(field_name, '/');
2261        if (opt_name)
2262                *opt_name++ = '\0';
2263
2264        *event = event_name;
2265        *field = field_name;
2266        *opt   = opt_name;
2267
2268        return 0;
2269}
2270
2271/* find match evsel using a given event name.  The event name can be:
2272 *   1. '%' + event index (e.g. '%1' for first event)
2273 *   2. full event name (e.g. sched:sched_switch)
2274 *   3. partial event name (should not contain ':')
2275 */
2276static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name)
2277{
2278        struct perf_evsel *evsel = NULL;
2279        struct perf_evsel *pos;
2280        bool full_name;
2281
2282        /* case 1 */
2283        if (event_name[0] == '%') {
2284                int nr = strtol(event_name+1, NULL, 0);
2285
2286                if (nr > evlist->nr_entries)
2287                        return NULL;
2288
2289                evsel = perf_evlist__first(evlist);
2290                while (--nr > 0)
2291                        evsel = perf_evsel__next(evsel);
2292
2293                return evsel;
2294        }
2295
2296        full_name = !!strchr(event_name, ':');
2297        evlist__for_each_entry(evlist, pos) {
2298                /* case 2 */
2299                if (full_name && !strcmp(pos->name, event_name))
2300                        return pos;
2301                /* case 3 */
2302                if (!full_name && strstr(pos->name, event_name)) {
2303                        if (evsel) {
2304                                pr_debug("'%s' event is ambiguous: it can be %s or %s\n",
2305                                         event_name, evsel->name, pos->name);
2306                                return NULL;
2307                        }
2308                        evsel = pos;
2309                }
2310        }
2311
2312        return evsel;
2313}
2314
2315static int __dynamic_dimension__add(struct perf_evsel *evsel,
2316                                    struct tep_format_field *field,
2317                                    bool raw_trace, int level)
2318{
2319        struct hpp_dynamic_entry *hde;
2320
2321        hde = __alloc_dynamic_entry(evsel, field, level);
2322        if (hde == NULL)
2323                return -ENOMEM;
2324
2325        hde->raw_trace = raw_trace;
2326
2327        perf_hpp__register_sort_field(&hde->hpp);
2328        return 0;
2329}
2330
2331static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace, int level)
2332{
2333        int ret;
2334        struct tep_format_field *field;
2335
2336        field = evsel->tp_format->format.fields;
2337        while (field) {
2338                ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
2339                if (ret < 0)
2340                        return ret;
2341
2342                field = field->next;
2343        }
2344        return 0;
2345}
2346
2347static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace,
2348                                  int level)
2349{
2350        int ret;
2351        struct perf_evsel *evsel;
2352
2353        evlist__for_each_entry(evlist, evsel) {
2354                if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
2355                        continue;
2356
2357                ret = add_evsel_fields(evsel, raw_trace, level);
2358                if (ret < 0)
2359                        return ret;
2360        }
2361        return 0;
2362}
2363
2364static int add_all_matching_fields(struct perf_evlist *evlist,
2365                                   char *field_name, bool raw_trace, int level)
2366{
2367        int ret = -ESRCH;
2368        struct perf_evsel *evsel;
2369        struct tep_format_field *field;
2370
2371        evlist__for_each_entry(evlist, evsel) {
2372                if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
2373                        continue;
2374
2375                field = tep_find_any_field(evsel->tp_format, field_name);
2376                if (field == NULL)
2377                        continue;
2378
2379                ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
2380                if (ret < 0)
2381                        break;
2382        }
2383        return ret;
2384}
2385
2386static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok,
2387                             int level)
2388{
2389        char *str, *event_name, *field_name, *opt_name;
2390        struct perf_evsel *evsel;
2391        struct tep_format_field *field;
2392        bool raw_trace = symbol_conf.raw_trace;
2393        int ret = 0;
2394
2395        if (evlist == NULL)
2396                return -ENOENT;
2397
2398        str = strdup(tok);
2399        if (str == NULL)
2400                return -ENOMEM;
2401
2402        if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) {
2403                ret = -EINVAL;
2404                goto out;
2405        }
2406
2407        if (opt_name) {
2408                if (strcmp(opt_name, "raw")) {
2409                        pr_debug("unsupported field option %s\n", opt_name);
2410                        ret = -EINVAL;
2411                        goto out;
2412                }
2413                raw_trace = true;
2414        }
2415
2416        if (!strcmp(field_name, "trace_fields")) {
2417                ret = add_all_dynamic_fields(evlist, raw_trace, level);
2418                goto out;
2419        }
2420
2421        if (event_name == NULL) {
2422                ret = add_all_matching_fields(evlist, field_name, raw_trace, level);
2423                goto out;
2424        }
2425
2426        evsel = find_evsel(evlist, event_name);
2427        if (evsel == NULL) {
2428                pr_debug("Cannot find event: %s\n", event_name);
2429                ret = -ENOENT;
2430                goto out;
2431        }
2432
2433        if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2434                pr_debug("%s is not a tracepoint event\n", event_name);
2435                ret = -EINVAL;
2436                goto out;
2437        }
2438
2439        if (!strcmp(field_name, "*")) {
2440                ret = add_evsel_fields(evsel, raw_trace, level);
2441        } else {
2442                field = tep_find_any_field(evsel->tp_format, field_name);
2443                if (field == NULL) {
2444                        pr_debug("Cannot find event field for %s.%s\n",
2445                                 event_name, field_name);
2446                        return -ENOENT;
2447                }
2448
2449                ret = __dynamic_dimension__add(evsel, field, raw_trace, level);
2450        }
2451
2452out:
2453        free(str);
2454        return ret;
2455}
2456
2457static int __sort_dimension__add(struct sort_dimension *sd,
2458                                 struct perf_hpp_list *list,
2459                                 int level)
2460{
2461        if (sd->taken)
2462                return 0;
2463
2464        if (__sort_dimension__add_hpp_sort(sd, list, level) < 0)
2465                return -1;
2466
2467        if (sd->entry->se_collapse)
2468                list->need_collapse = 1;
2469
2470        sd->taken = 1;
2471
2472        return 0;
2473}
2474
2475static int __hpp_dimension__add(struct hpp_dimension *hd,
2476                                struct perf_hpp_list *list,
2477                                int level)
2478{
2479        struct perf_hpp_fmt *fmt;
2480
2481        if (hd->taken)
2482                return 0;
2483
2484        fmt = __hpp_dimension__alloc_hpp(hd, level);
2485        if (!fmt)
2486                return -1;
2487
2488        hd->taken = 1;
2489        perf_hpp_list__register_sort_field(list, fmt);
2490        return 0;
2491}
2492
2493static int __sort_dimension__add_output(struct perf_hpp_list *list,
2494                                        struct sort_dimension *sd)
2495{
2496        if (sd->taken)
2497                return 0;
2498
2499        if (__sort_dimension__add_hpp_output(sd, list) < 0)
2500                return -1;
2501
2502        sd->taken = 1;
2503        return 0;
2504}
2505
2506static int __hpp_dimension__add_output(struct perf_hpp_list *list,
2507                                       struct hpp_dimension *hd)
2508{
2509        struct perf_hpp_fmt *fmt;
2510
2511        if (hd->taken)
2512                return 0;
2513
2514        fmt = __hpp_dimension__alloc_hpp(hd, 0);
2515        if (!fmt)
2516                return -1;
2517
2518        hd->taken = 1;
2519        perf_hpp_list__column_register(list, fmt);
2520        return 0;
2521}
2522
2523int hpp_dimension__add_output(unsigned col)
2524{
2525        BUG_ON(col >= PERF_HPP__MAX_INDEX);
2526        return __hpp_dimension__add_output(&perf_hpp_list, &hpp_sort_dimensions[col]);
2527}
2528
2529int sort_dimension__add(struct perf_hpp_list *list, const char *tok,
2530                        struct perf_evlist *evlist,
2531                        int level)
2532{
2533        unsigned int i;
2534
2535        for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2536                struct sort_dimension *sd = &common_sort_dimensions[i];
2537
2538                if (strncasecmp(tok, sd->name, strlen(tok)))
2539                        continue;
2540
2541                if (sd->entry == &sort_parent) {
2542                        int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED);
2543                        if (ret) {
2544                                char err[BUFSIZ];
2545
2546                                regerror(ret, &parent_regex, err, sizeof(err));
2547                                pr_err("Invalid regex: %s\n%s", parent_pattern, err);
2548                                return -EINVAL;
2549                        }
2550                        list->parent = 1;
2551                } else if (sd->entry == &sort_sym) {
2552                        list->sym = 1;
2553                        /*
2554                         * perf diff displays the performance difference amongst
2555                         * two or more perf.data files. Those files could come
2556                         * from different binaries. So we should not compare
2557                         * their ips, but the name of symbol.
2558                         */
2559                        if (sort__mode == SORT_MODE__DIFF)
2560                                sd->entry->se_collapse = sort__sym_sort;
2561
2562                } else if (sd->entry == &sort_dso) {
2563                        list->dso = 1;
2564                } else if (sd->entry == &sort_socket) {
2565                        list->socket = 1;
2566                } else if (sd->entry == &sort_thread) {
2567                        list->thread = 1;
2568                } else if (sd->entry == &sort_comm) {
2569                        list->comm = 1;
2570                }
2571
2572                return __sort_dimension__add(sd, list, level);
2573        }
2574
2575        for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2576                struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2577
2578                if (strncasecmp(tok, hd->name, strlen(tok)))
2579                        continue;
2580
2581                return __hpp_dimension__add(hd, list, level);
2582        }
2583
2584        for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2585                struct sort_dimension *sd = &bstack_sort_dimensions[i];
2586
2587                if (strncasecmp(tok, sd->name, strlen(tok)))
2588                        continue;
2589
2590                if (sort__mode != SORT_MODE__BRANCH)
2591                        return -EINVAL;
2592
2593                if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to)
2594                        list->sym = 1;
2595
2596                __sort_dimension__add(sd, list, level);
2597                return 0;
2598        }
2599
2600        for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2601                struct sort_dimension *sd = &memory_sort_dimensions[i];
2602
2603                if (strncasecmp(tok, sd->name, strlen(tok)))
2604                        continue;
2605
2606                if (sort__mode != SORT_MODE__MEMORY)
2607                        return -EINVAL;
2608
2609                if (sd->entry == &sort_mem_dcacheline && cacheline_size() == 0)
2610                        return -EINVAL;
2611
2612                if (sd->entry == &sort_mem_daddr_sym)
2613                        list->sym = 1;
2614
2615                __sort_dimension__add(sd, list, level);
2616                return 0;
2617        }
2618
2619        if (!add_dynamic_entry(evlist, tok, level))
2620                return 0;
2621
2622        return -ESRCH;
2623}
2624
2625static int setup_sort_list(struct perf_hpp_list *list, char *str,
2626                           struct perf_evlist *evlist)
2627{
2628        char *tmp, *tok;
2629        int ret = 0;
2630        int level = 0;
2631        int next_level = 1;
2632        bool in_group = false;
2633
2634        do {
2635                tok = str;
2636                tmp = strpbrk(str, "{}, ");
2637                if (tmp) {
2638                        if (in_group)
2639                                next_level = level;
2640                        else
2641                                next_level = level + 1;
2642
2643                        if (*tmp == '{')
2644                                in_group = true;
2645                        else if (*tmp == '}')
2646                                in_group = false;
2647
2648                        *tmp = '\0';
2649                        str = tmp + 1;
2650                }
2651
2652                if (*tok) {
2653                        ret = sort_dimension__add(list, tok, evlist, level);
2654                        if (ret == -EINVAL) {
2655                                if (!cacheline_size() && !strncasecmp(tok, "dcacheline", strlen(tok)))
2656                                        pr_err("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system");
2657                                else
2658                                        pr_err("Invalid --sort key: `%s'", tok);
2659                                break;
2660                        } else if (ret == -ESRCH) {
2661                                pr_err("Unknown --sort key: `%s'", tok);
2662                                break;
2663                        }
2664                }
2665
2666                level = next_level;
2667        } while (tmp);
2668
2669        return ret;
2670}
2671
2672static const char *get_default_sort_order(struct perf_evlist *evlist)
2673{
2674        const char *default_sort_orders[] = {
2675                default_sort_order,
2676                default_branch_sort_order,
2677                default_mem_sort_order,
2678                default_top_sort_order,
2679                default_diff_sort_order,
2680                default_tracepoint_sort_order,
2681        };
2682        bool use_trace = true;
2683        struct perf_evsel *evsel;
2684
2685        BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders));
2686
2687        if (evlist == NULL || perf_evlist__empty(evlist))
2688                goto out_no_evlist;
2689
2690        evlist__for_each_entry(evlist, evsel) {
2691                if (evsel->attr.type != PERF_TYPE_TRACEPOINT) {
2692                        use_trace = false;
2693                        break;
2694                }
2695        }
2696
2697        if (use_trace) {
2698                sort__mode = SORT_MODE__TRACEPOINT;
2699                if (symbol_conf.raw_trace)
2700                        return "trace_fields";
2701        }
2702out_no_evlist:
2703        return default_sort_orders[sort__mode];
2704}
2705
2706static int setup_sort_order(struct perf_evlist *evlist)
2707{
2708        char *new_sort_order;
2709
2710        /*
2711         * Append '+'-prefixed sort order to the default sort
2712         * order string.
2713         */
2714        if (!sort_order || is_strict_order(sort_order))
2715                return 0;
2716
2717        if (sort_order[1] == '\0') {
2718                pr_err("Invalid --sort key: `+'");
2719                return -EINVAL;
2720        }
2721
2722        /*
2723         * We allocate new sort_order string, but we never free it,
2724         * because it's checked over the rest of the code.
2725         */
2726        if (asprintf(&new_sort_order, "%s,%s",
2727                     get_default_sort_order(evlist), sort_order + 1) < 0) {
2728                pr_err("Not enough memory to set up --sort");
2729                return -ENOMEM;
2730        }
2731
2732        sort_order = new_sort_order;
2733        return 0;
2734}
2735
2736/*
2737 * Adds 'pre,' prefix into 'str' is 'pre' is
2738 * not already part of 'str'.
2739 */
2740static char *prefix_if_not_in(const char *pre, char *str)
2741{
2742        char *n;
2743
2744        if (!str || strstr(str, pre))
2745                return str;
2746
2747        if (asprintf(&n, "%s,%s", pre, str) < 0)
2748                return NULL;
2749
2750        free(str);
2751        return n;
2752}
2753
2754static char *setup_overhead(char *keys)
2755{
2756        if (sort__mode == SORT_MODE__DIFF)
2757                return keys;
2758
2759        keys = prefix_if_not_in("overhead", keys);
2760
2761        if (symbol_conf.cumulate_callchain)
2762                keys = prefix_if_not_in("overhead_children", keys);
2763
2764        return keys;
2765}
2766
2767static int __setup_sorting(struct perf_evlist *evlist)
2768{
2769        char *str;
2770        const char *sort_keys;
2771        int ret = 0;
2772
2773        ret = setup_sort_order(evlist);
2774        if (ret)
2775                return ret;
2776
2777        sort_keys = sort_order;
2778        if (sort_keys == NULL) {
2779                if (is_strict_order(field_order)) {
2780                        /*
2781                         * If user specified field order but no sort order,
2782                         * we'll honor it and not add default sort orders.
2783                         */
2784                        return 0;
2785                }
2786
2787                sort_keys = get_default_sort_order(evlist);
2788        }
2789
2790        str = strdup(sort_keys);
2791        if (str == NULL) {
2792                pr_err("Not enough memory to setup sort keys");
2793                return -ENOMEM;
2794        }
2795
2796        /*
2797         * Prepend overhead fields for backward compatibility.
2798         */
2799        if (!is_strict_order(field_order)) {
2800                str = setup_overhead(str);
2801                if (str == NULL) {
2802                        pr_err("Not enough memory to setup overhead keys");
2803                        return -ENOMEM;
2804                }
2805        }
2806
2807        ret = setup_sort_list(&perf_hpp_list, str, evlist);
2808
2809        free(str);
2810        return ret;
2811}
2812
2813void perf_hpp__set_elide(int idx, bool elide)
2814{
2815        struct perf_hpp_fmt *fmt;
2816        struct hpp_sort_entry *hse;
2817
2818        perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
2819                if (!perf_hpp__is_sort_entry(fmt))
2820                        continue;
2821
2822                hse = container_of(fmt, struct hpp_sort_entry, hpp);
2823                if (hse->se->se_width_idx == idx) {
2824                        fmt->elide = elide;
2825                        break;
2826                }
2827        }
2828}
2829
2830static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp)
2831{
2832        if (list && strlist__nr_entries(list) == 1) {
2833                if (fp != NULL)
2834                        fprintf(fp, "# %s: %s\n", list_name,
2835                                strlist__entry(list, 0)->s);
2836                return true;
2837        }
2838        return false;
2839}
2840
2841static bool get_elide(int idx, FILE *output)
2842{
2843        switch (idx) {
2844        case HISTC_SYMBOL:
2845                return __get_elide(symbol_conf.sym_list, "symbol", output);
2846        case HISTC_DSO:
2847                return __get_elide(symbol_conf.dso_list, "dso", output);
2848        case HISTC_COMM:
2849                return __get_elide(symbol_conf.comm_list, "comm", output);
2850        default:
2851                break;
2852        }
2853
2854        if (sort__mode != SORT_MODE__BRANCH)
2855                return false;
2856
2857        switch (idx) {
2858        case HISTC_SYMBOL_FROM:
2859                return __get_elide(symbol_conf.sym_from_list, "sym_from", output);
2860        case HISTC_SYMBOL_TO:
2861                return __get_elide(symbol_conf.sym_to_list, "sym_to", output);
2862        case HISTC_DSO_FROM:
2863                return __get_elide(symbol_conf.dso_from_list, "dso_from", output);
2864        case HISTC_DSO_TO:
2865                return __get_elide(symbol_conf.dso_to_list, "dso_to", output);
2866        default:
2867                break;
2868        }
2869
2870        return false;
2871}
2872
2873void sort__setup_elide(FILE *output)
2874{
2875        struct perf_hpp_fmt *fmt;
2876        struct hpp_sort_entry *hse;
2877
2878        perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
2879                if (!perf_hpp__is_sort_entry(fmt))
2880                        continue;
2881
2882                hse = container_of(fmt, struct hpp_sort_entry, hpp);
2883                fmt->elide = get_elide(hse->se->se_width_idx, output);
2884        }
2885
2886        /*
2887         * It makes no sense to elide all of sort entries.
2888         * Just revert them to show up again.
2889         */
2890        perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
2891                if (!perf_hpp__is_sort_entry(fmt))
2892                        continue;
2893
2894                if (!fmt->elide)
2895                        return;
2896        }
2897
2898        perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
2899                if (!perf_hpp__is_sort_entry(fmt))
2900                        continue;
2901
2902                fmt->elide = false;
2903        }
2904}
2905
2906int output_field_add(struct perf_hpp_list *list, char *tok)
2907{
2908        unsigned int i;
2909
2910        for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) {
2911                struct sort_dimension *sd = &common_sort_dimensions[i];
2912
2913                if (strncasecmp(tok, sd->name, strlen(tok)))
2914                        continue;
2915
2916                return __sort_dimension__add_output(list, sd);
2917        }
2918
2919        for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
2920                struct hpp_dimension *hd = &hpp_sort_dimensions[i];
2921
2922                if (strncasecmp(tok, hd->name, strlen(tok)))
2923                        continue;
2924
2925                return __hpp_dimension__add_output(list, hd);
2926        }
2927
2928        for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
2929                struct sort_dimension *sd = &bstack_sort_dimensions[i];
2930
2931                if (strncasecmp(tok, sd->name, strlen(tok)))
2932                        continue;
2933
2934                return __sort_dimension__add_output(list, sd);
2935        }
2936
2937        for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
2938                struct sort_dimension *sd = &memory_sort_dimensions[i];
2939
2940                if (strncasecmp(tok, sd->name, strlen(tok)))
2941                        continue;
2942
2943                return __sort_dimension__add_output(list, sd);
2944        }
2945
2946        return -ESRCH;
2947}
2948
2949static int setup_output_list(struct perf_hpp_list *list, char *str)
2950{
2951        char *tmp, *tok;
2952        int ret = 0;
2953
2954        for (tok = strtok_r(str, ", ", &tmp);
2955                        tok; tok = strtok_r(NULL, ", ", &tmp)) {
2956                ret = output_field_add(list, tok);
2957                if (ret == -EINVAL) {
2958                        ui__error("Invalid --fields key: `%s'", tok);
2959                        break;
2960                } else if (ret == -ESRCH) {
2961                        ui__error("Unknown --fields key: `%s'", tok);
2962                        break;
2963                }
2964        }
2965
2966        return ret;
2967}
2968
2969void reset_dimensions(void)
2970{
2971        unsigned int i;
2972
2973        for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++)
2974                common_sort_dimensions[i].taken = 0;
2975
2976        for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++)
2977                hpp_sort_dimensions[i].taken = 0;
2978
2979        for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++)
2980                bstack_sort_dimensions[i].taken = 0;
2981
2982        for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++)
2983                memory_sort_dimensions[i].taken = 0;
2984}
2985
2986bool is_strict_order(const char *order)
2987{
2988        return order && (*order != '+');
2989}
2990
2991static int __setup_output_field(void)
2992{
2993        char *str, *strp;
2994        int ret = -EINVAL;
2995
2996        if (field_order == NULL)
2997                return 0;
2998
2999        strp = str = strdup(field_order);
3000        if (str == NULL) {
3001                pr_err("Not enough memory to setup output fields");
3002                return -ENOMEM;
3003        }
3004
3005        if (!is_strict_order(field_order))
3006                strp++;
3007
3008        if (!strlen(strp)) {
3009                pr_err("Invalid --fields key: `+'");
3010                goto out;
3011        }
3012
3013        ret = setup_output_list(&perf_hpp_list, strp);
3014
3015out:
3016        free(str);
3017        return ret;
3018}
3019
3020int setup_sorting(struct perf_evlist *evlist)
3021{
3022        int err;
3023
3024        err = __setup_sorting(evlist);
3025        if (err < 0)
3026                return err;
3027
3028        if (parent_pattern != default_parent_pattern) {
3029                err = sort_dimension__add(&perf_hpp_list, "parent", evlist, -1);
3030                if (err < 0)
3031                        return err;
3032        }
3033
3034        reset_dimensions();
3035
3036        /*
3037         * perf diff doesn't use default hpp output fields.
3038         */
3039        if (sort__mode != SORT_MODE__DIFF)
3040                perf_hpp__init();
3041
3042        err = __setup_output_field();
3043        if (err < 0)
3044                return err;
3045
3046        /* copy sort keys to output fields */
3047        perf_hpp__setup_output_field(&perf_hpp_list);
3048        /* and then copy output fields to sort keys */
3049        perf_hpp__append_sort_keys(&perf_hpp_list);
3050
3051        /* setup hists-specific output fields */
3052        if (perf_hpp__setup_hists_formats(&perf_hpp_list, evlist) < 0)
3053                return -1;
3054
3055        return 0;
3056}
3057
3058void reset_output_field(void)
3059{
3060        perf_hpp_list.need_collapse = 0;
3061        perf_hpp_list.parent = 0;
3062        perf_hpp_list.sym = 0;
3063        perf_hpp_list.dso = 0;
3064
3065        field_order = NULL;
3066        sort_order = NULL;
3067
3068        reset_dimensions();
3069        perf_hpp__reset_output_field(&perf_hpp_list);
3070}
3071