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