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