1 // SPDX-License-Identifier: GPL-2.0 2 #include "sort.h" 3 4 #include <ctype.h> 5 #include <errno.h> 6 #include <inttypes.h> 7 #include <stdlib.h> 8 9 #include <elf.h> 10 #include <linux/kernel.h> 11 #include <linux/mman.h> 12 #include <linux/string.h> 13 #include <linux/time64.h> 14 15 #include <regex.h> 16 17 #include "annotate-data.h" 18 #include "annotate.h" 19 #include "branch.h" 20 #include "cacheline.h" 21 #include "cgroup.h" 22 #include "comm.h" 23 #include "debug.h" 24 #include "dso.h" 25 #include "event.h" 26 #include "evlist.h" 27 #include "evsel.h" 28 #include "hist.h" 29 #include "machine.h" 30 #include "map.h" 31 #include "map_symbol.h" 32 #include "maps.h" 33 #include "mem-events.h" 34 #include "mem-info.h" 35 #include "session.h" 36 #include "srcline.h" 37 #include "strbuf.h" 38 #include "strlist.h" 39 #include "symbol.h" 40 #include "thread.h" 41 #include "time-utils.h" 42 #include "trace-event.h" 43 44 #ifdef HAVE_LIBTRACEEVENT 45 #include <event-parse.h> 46 #endif 47 48 regex_t parent_regex; 49 const char default_parent_pattern[] = "^sys_|^do_page_fault"; 50 const char *parent_pattern = default_parent_pattern; 51 const char *default_sort_order = "comm,dso,symbol"; 52 static const char default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cycles"; 53 const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked,blocked,local_ins_lat,local_p_stage_cyc"; 54 static const char default_top_sort_order[] = "dso,symbol"; 55 static const char default_diff_sort_order[] = "dso,symbol"; 56 static const char default_tracepoint_sort_order[] = "trace"; 57 const char *sort_order; 58 const char *field_order; 59 regex_t ignore_callees_regex; 60 int have_ignore_callees = 0; 61 enum sort_mode sort__mode = SORT_MODE__NORMAL; 62 static const char *const dynamic_headers[] = {"local_ins_lat", "ins_lat", "local_p_stage_cyc", "p_stage_cyc"}; 63 static const char *const arch_specific_sort_keys[] = {"local_p_stage_cyc", "p_stage_cyc"}; 64 65 /* 66 * Some architectures have Adjacent Cacheline Prefetch feature, which 67 * behaves like the cacheline size is doubled. Enable this flag to 68 * check things in double cacheline granularity. 69 */ 70 bool chk_double_cl; 71 72 /* 73 * Replaces all occurrences of a char used with the: 74 * 75 * -t, --field-separator 76 * 77 * option, that uses a special separator character and don't pad with spaces, 78 * replacing all occurrences of this separator in symbol names (and other 79 * output) with a '.' character, that thus it's the only non valid separator. 80 */ 81 static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) 82 { 83 int n; 84 va_list ap; 85 86 va_start(ap, fmt); 87 n = vsnprintf(bf, size, fmt, ap); 88 if (symbol_conf.field_sep && n > 0) { 89 char *sep = bf; 90 91 while (1) { 92 sep = strchr(sep, *symbol_conf.field_sep); 93 if (sep == NULL) 94 break; 95 *sep = '.'; 96 } 97 } 98 va_end(ap); 99 100 if (n >= (int)size) 101 return size - 1; 102 return n; 103 } 104 105 static int64_t cmp_null(const void *l, const void *r) 106 { 107 if (!l && !r) 108 return 0; 109 else if (!l) 110 return -1; 111 else 112 return 1; 113 } 114 115 /* --sort pid */ 116 117 static int64_t 118 sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) 119 { 120 return thread__tid(right->thread) - thread__tid(left->thread); 121 } 122 123 static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf, 124 size_t size, unsigned int width) 125 { 126 const char *comm = thread__comm_str(he->thread); 127 128 width = max(7U, width) - 8; 129 return repsep_snprintf(bf, size, "%7d:%-*.*s", thread__tid(he->thread), 130 width, width, comm ?: ""); 131 } 132 133 static int hist_entry__thread_filter(struct hist_entry *he, int type, const void *arg) 134 { 135 const struct thread *th = arg; 136 137 if (type != HIST_FILTER__THREAD) 138 return -1; 139 140 return th && !RC_CHK_EQUAL(he->thread, th); 141 } 142 143 struct sort_entry sort_thread = { 144 .se_header = " Pid:Command", 145 .se_cmp = sort__thread_cmp, 146 .se_snprintf = hist_entry__thread_snprintf, 147 .se_filter = hist_entry__thread_filter, 148 .se_width_idx = HISTC_THREAD, 149 }; 150 151 /* --sort tgid */ 152 153 static int64_t 154 sort__tgid_cmp(struct hist_entry *left, struct hist_entry *right) 155 { 156 return thread__pid(right->thread) - thread__pid(left->thread); 157 } 158 159 static int hist_entry__tgid_snprintf(struct hist_entry *he, char *bf, 160 size_t size, unsigned int width) 161 { 162 int tgid = thread__pid(he->thread); 163 const char *comm = NULL; 164 165 /* display comm of the thread-group leader */ 166 if (thread__pid(he->thread) == thread__tid(he->thread)) { 167 comm = thread__comm_str(he->thread); 168 } else { 169 struct maps *maps = thread__maps(he->thread); 170 struct thread *leader = machine__find_thread(maps__machine(maps), 171 tgid, tgid); 172 if (leader) { 173 comm = thread__comm_str(leader); 174 thread__put(leader); 175 } 176 } 177 width = max(7U, width) - 8; 178 return repsep_snprintf(bf, size, "%7d:%-*.*s", tgid, width, width, comm ?: ""); 179 } 180 181 static struct sort_entry sort_tgid = { 182 .se_header = " Tgid:Command", 183 .se_cmp = sort__tgid_cmp, 184 .se_snprintf = hist_entry__tgid_snprintf, 185 .se_width_idx = HISTC_TGID, 186 }; 187 188 /* --sort simd */ 189 190 static int64_t 191 sort__simd_cmp(struct hist_entry *left, struct hist_entry *right) 192 { 193 if (left->simd_flags.arch != right->simd_flags.arch) 194 return (int64_t) left->simd_flags.arch - right->simd_flags.arch; 195 196 return (int64_t) left->simd_flags.pred - right->simd_flags.pred; 197 } 198 199 static const char *hist_entry__get_simd_name(struct simd_flags *simd_flags) 200 { 201 u64 arch = simd_flags->arch; 202 203 if (arch == SIMD_OP_FLAGS_ARCH_SVE) 204 return "SVE"; 205 else if (arch == SIMD_OP_FLAGS_ARCH_SME) 206 return "SME"; 207 else if (arch == SIMD_OP_FLAGS_ARCH_ASE) 208 return "ASE"; 209 else 210 return "n/a"; 211 } 212 213 static int hist_entry__simd_snprintf(struct hist_entry *he, char *bf, 214 size_t size, unsigned int width __maybe_unused) 215 { 216 const char *name; 217 const char *pred_str = "."; 218 219 if (!he->simd_flags.arch) 220 return repsep_snprintf(bf, size, ""); 221 222 name = hist_entry__get_simd_name(&he->simd_flags); 223 224 if (he->simd_flags.pred == SIMD_OP_FLAGS_PRED_EMPTY) 225 pred_str = "e"; 226 else if (he->simd_flags.pred == SIMD_OP_FLAGS_PRED_PARTIAL) 227 pred_str = "p"; 228 else if (he->simd_flags.pred == SIMD_OP_FLAGS_PRED_DISABLED) 229 pred_str = "d"; 230 else if (he->simd_flags.pred == SIMD_OP_FLAGS_PRED_FULL) 231 pred_str = "f"; 232 233 return repsep_snprintf(bf, size, "[%s] %s", pred_str, name); 234 } 235 236 static struct sort_entry sort_simd = { 237 .se_header = "Simd ", 238 .se_cmp = sort__simd_cmp, 239 .se_snprintf = hist_entry__simd_snprintf, 240 .se_width_idx = HISTC_SIMD, 241 }; 242 243 /* --sort comm */ 244 245 /* 246 * We can't use pointer comparison in functions below, 247 * because it gives different results based on pointer 248 * values, which could break some sorting assumptions. 249 */ 250 static int64_t 251 sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) 252 { 253 return strcmp(comm__str(right->comm), comm__str(left->comm)); 254 } 255 256 static int64_t 257 sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) 258 { 259 return strcmp(comm__str(right->comm), comm__str(left->comm)); 260 } 261 262 static int64_t 263 sort__comm_sort(struct hist_entry *left, struct hist_entry *right) 264 { 265 return strcmp(comm__str(right->comm), comm__str(left->comm)); 266 } 267 268 static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, 269 size_t size, unsigned int width) 270 { 271 return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm)); 272 } 273 274 struct sort_entry sort_comm = { 275 .se_header = "Command", 276 .se_cmp = sort__comm_cmp, 277 .se_collapse = sort__comm_collapse, 278 .se_sort = sort__comm_sort, 279 .se_snprintf = hist_entry__comm_snprintf, 280 .se_filter = hist_entry__thread_filter, 281 .se_width_idx = HISTC_COMM, 282 }; 283 284 /* --sort comm_nodigit */ 285 286 size_t sort__comm_nodigit_len(struct hist_entry *entry) 287 { 288 const char *comm = comm__str(entry->comm); 289 size_t index, len_nodigit = 0; 290 bool in_number = false; 291 292 if (!comm) 293 return 0; 294 295 for (index = 0; comm[index]; index++) { 296 if (!isdigit((unsigned char)comm[index])) { 297 in_number = false; 298 len_nodigit++; 299 } else if (!in_number) { 300 in_number = true; 301 len_nodigit += 3; /* <N> */ 302 } 303 } 304 305 return len_nodigit; 306 } 307 308 static int64_t strcmp_nodigit(const char *left, const char *right) 309 { 310 for (;;) { 311 while (*left && isdigit((unsigned char)*left)) 312 left++; 313 while (*right && isdigit((unsigned char)*right)) 314 right++; 315 if (*left == *right && !*left) { 316 return 0; 317 } else if (*left == *right) { 318 left++; 319 right++; 320 } else { 321 return (int64_t)((unsigned char)*left - (unsigned char)*right); 322 } 323 } 324 } 325 326 static int64_t 327 sort__comm_nodigit_cmp(struct hist_entry *left, struct hist_entry *right) 328 { 329 return strcmp_nodigit(comm__str(right->comm), comm__str(left->comm)); 330 } 331 332 static int64_t 333 sort__comm_nodigit_collapse(struct hist_entry *left, struct hist_entry *right) 334 { 335 return strcmp_nodigit(comm__str(right->comm), comm__str(left->comm)); 336 } 337 338 static int64_t 339 sort__comm_nodigit_sort(struct hist_entry *left, struct hist_entry *right) 340 { 341 return strcmp_nodigit(comm__str(right->comm), comm__str(left->comm)); 342 } 343 344 static int hist_entry__comm_nodigit_snprintf(struct hist_entry *he, char *bf, 345 size_t size, unsigned int width) 346 { 347 int ret = 0; 348 unsigned int print_len, printed = 0, start = 0, end = 0; 349 bool in_digit; 350 const char *comm = comm__str(he->comm), *print; 351 352 while (printed < width && printed < size && comm[start]) { 353 in_digit = !!isdigit((unsigned char)comm[start]); 354 end = start + 1; 355 while (comm[end] && !!isdigit((unsigned char)comm[end]) == in_digit) 356 end++; 357 if (in_digit) { 358 print_len = 3; /* <N> */ 359 print = "<N>"; 360 } else { 361 print_len = end - start; 362 print = &comm[start]; 363 } 364 print_len = min(print_len, width - printed); 365 ret = repsep_snprintf(bf + printed, size - printed, "%-.*s", 366 print_len, print); 367 if (ret < 0) 368 return ret; 369 start = end; 370 printed += ret; 371 } 372 /* Pad to width if necessary */ 373 if (printed < width && printed < size) { 374 ret = repsep_snprintf(bf + printed, size - printed, "%-*.*s", 375 width - printed, width - printed, ""); 376 if (ret < 0) 377 return ret; 378 printed += ret; 379 } 380 return printed; 381 } 382 383 struct sort_entry sort_comm_nodigit = { 384 .se_header = "CommandNoDigit", 385 .se_cmp = sort__comm_nodigit_cmp, 386 .se_collapse = sort__comm_nodigit_collapse, 387 .se_sort = sort__comm_nodigit_sort, 388 .se_snprintf = hist_entry__comm_nodigit_snprintf, 389 .se_filter = hist_entry__thread_filter, 390 .se_width_idx = HISTC_COMM_NODIGIT, 391 }; 392 393 /* --sort dso */ 394 395 static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) 396 { 397 struct dso *dso_l = map_l ? map__dso(map_l) : NULL; 398 struct dso *dso_r = map_r ? map__dso(map_r) : NULL; 399 const char *dso_name_l, *dso_name_r; 400 401 if (!dso_l || !dso_r) 402 return cmp_null(dso_r, dso_l); 403 404 if (verbose > 0) { 405 dso_name_l = dso__long_name(dso_l); 406 dso_name_r = dso__long_name(dso_r); 407 } else { 408 dso_name_l = dso__short_name(dso_l); 409 dso_name_r = dso__short_name(dso_r); 410 } 411 412 return strcmp(dso_name_l, dso_name_r); 413 } 414 415 static int64_t 416 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 417 { 418 return _sort__dso_cmp(right->ms.map, left->ms.map); 419 } 420 421 static int _hist_entry__dso_snprintf(struct map *map, char *bf, 422 size_t size, unsigned int width) 423 { 424 const struct dso *dso = map ? map__dso(map) : NULL; 425 const char *dso_name = "[unknown]"; 426 427 if (dso) 428 dso_name = verbose > 0 ? dso__long_name(dso) : dso__short_name(dso); 429 430 return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name); 431 } 432 433 static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf, 434 size_t size, unsigned int width) 435 { 436 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width); 437 } 438 439 static int hist_entry__dso_filter(struct hist_entry *he, int type, const void *arg) 440 { 441 const struct dso *dso = arg; 442 443 if (type != HIST_FILTER__DSO) 444 return -1; 445 446 return dso && (!he->ms.map || map__dso(he->ms.map) != dso); 447 } 448 449 struct sort_entry sort_dso = { 450 .se_header = "Shared Object", 451 .se_cmp = sort__dso_cmp, 452 .se_snprintf = hist_entry__dso_snprintf, 453 .se_filter = hist_entry__dso_filter, 454 .se_width_idx = HISTC_DSO, 455 }; 456 457 /* --sort symbol */ 458 459 static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip) 460 { 461 return (int64_t)(right_ip - left_ip); 462 } 463 464 int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r) 465 { 466 if (!sym_l || !sym_r) 467 return cmp_null(sym_l, sym_r); 468 469 if (sym_l == sym_r) 470 return 0; 471 472 if (symbol__inlined(sym_l) || symbol__inlined(sym_r)) { 473 int ret = strcmp(sym_l->name, sym_r->name); 474 475 if (ret) 476 return ret; 477 if ((sym_l->start <= sym_r->end) && (sym_l->end >= sym_r->start)) 478 return 0; 479 } 480 481 if (sym_l->start != sym_r->start) 482 return (int64_t)(sym_r->start - sym_l->start); 483 484 return (int64_t)(sym_r->end - sym_l->end); 485 } 486 487 static int64_t 488 sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 489 { 490 int64_t ret; 491 492 if (!left->ms.sym && !right->ms.sym) 493 return _sort__addr_cmp(left->ip, right->ip); 494 495 /* 496 * comparing symbol address alone is not enough since it's a 497 * relative address within a dso. 498 */ 499 if (!hists__has(left->hists, dso)) { 500 ret = sort__dso_cmp(left, right); 501 if (ret != 0) 502 return ret; 503 } 504 505 return _sort__sym_cmp(left->ms.sym, right->ms.sym); 506 } 507 508 static int64_t 509 sort__sym_sort(struct hist_entry *left, struct hist_entry *right) 510 { 511 if (!left->ms.sym || !right->ms.sym) 512 return cmp_null(left->ms.sym, right->ms.sym); 513 514 return strcmp(right->ms.sym->name, left->ms.sym->name); 515 } 516 517 static int _hist_entry__sym_snprintf(struct map_symbol *ms, 518 u64 ip, char level, char *bf, size_t size, 519 unsigned int width) 520 { 521 struct symbol *sym = ms->sym; 522 struct map *map = ms->map; 523 size_t ret = 0; 524 525 if (verbose > 0) { 526 struct dso *dso = map ? map__dso(map) : NULL; 527 char o = dso ? dso__symtab_origin(dso) : '!'; 528 u64 rip = ip; 529 530 if (dso && dso__kernel(dso) && dso__adjust_symbols(dso)) 531 rip = map__unmap_ip(map, ip); 532 533 ret += repsep_snprintf(bf, size, "%-#*llx %c ", 534 BITS_PER_LONG / 4 + 2, rip, o); 535 } 536 537 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level); 538 if (sym && map) { 539 if (symbol__type(sym) == STT_OBJECT) { 540 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name); 541 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx", 542 ip - map__unmap_ip(map, sym->start)); 543 } else { 544 ret += repsep_snprintf(bf + ret, size - ret, "%.*s", 545 width - ret, 546 sym->name); 547 if (symbol__inlined(sym)) 548 ret += repsep_snprintf(bf + ret, size - ret, 549 " (inlined)"); 550 } 551 } else { 552 size_t len = BITS_PER_LONG / 4; 553 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", 554 len, ip); 555 } 556 557 return ret; 558 } 559 560 int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) 561 { 562 return _hist_entry__sym_snprintf(&he->ms, he->ip, 563 he->level, bf, size, width); 564 } 565 566 static int hist_entry__sym_filter(struct hist_entry *he, int type, const void *arg) 567 { 568 const char *sym = arg; 569 570 if (type != HIST_FILTER__SYMBOL) 571 return -1; 572 573 return sym && (!he->ms.sym || !strstr(he->ms.sym->name, sym)); 574 } 575 576 struct sort_entry sort_sym = { 577 .se_header = "Symbol", 578 .se_cmp = sort__sym_cmp, 579 .se_sort = sort__sym_sort, 580 .se_snprintf = hist_entry__sym_snprintf, 581 .se_filter = hist_entry__sym_filter, 582 .se_width_idx = HISTC_SYMBOL, 583 }; 584 585 /* --sort symoff */ 586 587 static int64_t 588 sort__symoff_cmp(struct hist_entry *left, struct hist_entry *right) 589 { 590 int64_t ret; 591 592 ret = sort__sym_cmp(left, right); 593 if (ret) 594 return ret; 595 596 return left->ip - right->ip; 597 } 598 599 static int64_t 600 sort__symoff_sort(struct hist_entry *left, struct hist_entry *right) 601 { 602 int64_t ret; 603 604 ret = sort__sym_sort(left, right); 605 if (ret) 606 return ret; 607 608 return left->ip - right->ip; 609 } 610 611 static int 612 hist_entry__symoff_snprintf(struct hist_entry *he, char *bf, size_t size, unsigned int width) 613 { 614 struct symbol *sym = he->ms.sym; 615 616 if (sym == NULL) 617 return repsep_snprintf(bf, size, "[%c] %-#.*llx", he->level, width - 4, he->ip); 618 619 return repsep_snprintf(bf, size, "[%c] %s+0x%llx", he->level, sym->name, he->ip - sym->start); 620 } 621 622 static struct sort_entry sort_sym_offset = { 623 .se_header = "Symbol Offset", 624 .se_cmp = sort__symoff_cmp, 625 .se_sort = sort__symoff_sort, 626 .se_snprintf = hist_entry__symoff_snprintf, 627 .se_filter = hist_entry__sym_filter, 628 .se_width_idx = HISTC_SYMBOL_OFFSET, 629 }; 630 631 /* --sort srcline */ 632 633 char *hist_entry__srcline(struct hist_entry *he) 634 { 635 return map__srcline(he->ms.map, he->ip, he->ms.sym); 636 } 637 638 static int64_t 639 sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) 640 { 641 int64_t ret; 642 643 ret = _sort__addr_cmp(left->ip, right->ip); 644 if (ret) 645 return ret; 646 647 return sort__dso_cmp(left, right); 648 } 649 650 static int64_t 651 sort__srcline_collapse(struct hist_entry *left, struct hist_entry *right) 652 { 653 if (!left->srcline) 654 left->srcline = hist_entry__srcline(left); 655 if (!right->srcline) 656 right->srcline = hist_entry__srcline(right); 657 658 return strcmp(right->srcline, left->srcline); 659 } 660 661 static int64_t 662 sort__srcline_sort(struct hist_entry *left, struct hist_entry *right) 663 { 664 return sort__srcline_collapse(left, right); 665 } 666 667 static void 668 sort__srcline_init(struct hist_entry *he) 669 { 670 if (!he->srcline) 671 he->srcline = hist_entry__srcline(he); 672 } 673 674 static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, 675 size_t size, unsigned int width) 676 { 677 return repsep_snprintf(bf, size, "%-.*s", width, he->srcline); 678 } 679 680 struct sort_entry sort_srcline = { 681 .se_header = "Source:Line", 682 .se_cmp = sort__srcline_cmp, 683 .se_collapse = sort__srcline_collapse, 684 .se_sort = sort__srcline_sort, 685 .se_init = sort__srcline_init, 686 .se_snprintf = hist_entry__srcline_snprintf, 687 .se_width_idx = HISTC_SRCLINE, 688 }; 689 690 /* --sort srcline_from */ 691 692 static char *addr_map_symbol__srcline(struct addr_map_symbol *ams) 693 { 694 return map__srcline(ams->ms.map, ams->al_addr, ams->ms.sym); 695 } 696 697 static int64_t 698 sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right) 699 { 700 return left->branch_info->from.addr - right->branch_info->from.addr; 701 } 702 703 static int64_t 704 sort__srcline_from_collapse(struct hist_entry *left, struct hist_entry *right) 705 { 706 if (!left->branch_info->srcline_from) 707 left->branch_info->srcline_from = addr_map_symbol__srcline(&left->branch_info->from); 708 709 if (!right->branch_info->srcline_from) 710 right->branch_info->srcline_from = addr_map_symbol__srcline(&right->branch_info->from); 711 712 return strcmp(right->branch_info->srcline_from, left->branch_info->srcline_from); 713 } 714 715 static int64_t 716 sort__srcline_from_sort(struct hist_entry *left, struct hist_entry *right) 717 { 718 return sort__srcline_from_collapse(left, right); 719 } 720 721 static void sort__srcline_from_init(struct hist_entry *he) 722 { 723 if (!he->branch_info->srcline_from) 724 he->branch_info->srcline_from = addr_map_symbol__srcline(&he->branch_info->from); 725 } 726 727 static int hist_entry__srcline_from_snprintf(struct hist_entry *he, char *bf, 728 size_t size, unsigned int width) 729 { 730 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_from); 731 } 732 733 static struct sort_entry sort_srcline_from = { 734 .se_header = "From Source:Line", 735 .se_cmp = sort__srcline_from_cmp, 736 .se_collapse = sort__srcline_from_collapse, 737 .se_sort = sort__srcline_from_sort, 738 .se_init = sort__srcline_from_init, 739 .se_snprintf = hist_entry__srcline_from_snprintf, 740 .se_width_idx = HISTC_SRCLINE_FROM, 741 }; 742 743 /* --sort srcline_to */ 744 745 static int64_t 746 sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right) 747 { 748 return left->branch_info->to.addr - right->branch_info->to.addr; 749 } 750 751 static int64_t 752 sort__srcline_to_collapse(struct hist_entry *left, struct hist_entry *right) 753 { 754 if (!left->branch_info->srcline_to) 755 left->branch_info->srcline_to = addr_map_symbol__srcline(&left->branch_info->to); 756 757 if (!right->branch_info->srcline_to) 758 right->branch_info->srcline_to = addr_map_symbol__srcline(&right->branch_info->to); 759 760 return strcmp(right->branch_info->srcline_to, left->branch_info->srcline_to); 761 } 762 763 static int64_t 764 sort__srcline_to_sort(struct hist_entry *left, struct hist_entry *right) 765 { 766 return sort__srcline_to_collapse(left, right); 767 } 768 769 static void sort__srcline_to_init(struct hist_entry *he) 770 { 771 if (!he->branch_info->srcline_to) 772 he->branch_info->srcline_to = addr_map_symbol__srcline(&he->branch_info->to); 773 } 774 775 static int hist_entry__srcline_to_snprintf(struct hist_entry *he, char *bf, 776 size_t size, unsigned int width) 777 { 778 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->branch_info->srcline_to); 779 } 780 781 static struct sort_entry sort_srcline_to = { 782 .se_header = "To Source:Line", 783 .se_cmp = sort__srcline_to_cmp, 784 .se_collapse = sort__srcline_to_collapse, 785 .se_sort = sort__srcline_to_sort, 786 .se_init = sort__srcline_to_init, 787 .se_snprintf = hist_entry__srcline_to_snprintf, 788 .se_width_idx = HISTC_SRCLINE_TO, 789 }; 790 791 static int hist_entry__sym_ipc_snprintf(struct hist_entry *he, char *bf, 792 size_t size, unsigned int width) 793 { 794 795 struct symbol *sym = he->ms.sym; 796 struct annotated_branch *branch; 797 double ipc = 0.0, coverage = 0.0; 798 char tmp[64]; 799 800 if (!sym) 801 return repsep_snprintf(bf, size, "%-*s", width, "-"); 802 803 branch = symbol__annotation(sym)->branch; 804 805 if (branch && branch->hit_cycles) 806 ipc = branch->hit_insn / ((double)branch->hit_cycles); 807 808 if (branch && branch->total_insn) { 809 coverage = branch->cover_insn * 100.0 / 810 ((double)branch->total_insn); 811 } 812 813 snprintf(tmp, sizeof(tmp), "%-5.2f [%5.1f%%]", ipc, coverage); 814 return repsep_snprintf(bf, size, "%-*s", width, tmp); 815 } 816 817 static struct sort_entry sort_sym_ipc = { 818 .se_header = "IPC [IPC Coverage]", 819 .se_cmp = sort__sym_cmp, 820 .se_snprintf = hist_entry__sym_ipc_snprintf, 821 .se_width_idx = HISTC_SYMBOL_IPC, 822 }; 823 824 static int hist_entry__sym_ipc_null_snprintf(struct hist_entry *he 825 __maybe_unused, 826 char *bf, size_t size, 827 unsigned int width) 828 { 829 char tmp[64]; 830 831 snprintf(tmp, sizeof(tmp), "%-5s %2s", "-", "-"); 832 return repsep_snprintf(bf, size, "%-*s", width, tmp); 833 } 834 835 static struct sort_entry sort_sym_ipc_null = { 836 .se_header = "IPC [IPC Coverage]", 837 .se_cmp = sort__sym_cmp, 838 .se_snprintf = hist_entry__sym_ipc_null_snprintf, 839 .se_width_idx = HISTC_SYMBOL_IPC, 840 }; 841 842 /* --sort callchain_branch_predicted */ 843 844 static int64_t 845 sort__callchain_branch_predicted_cmp(struct hist_entry *left __maybe_unused, 846 struct hist_entry *right __maybe_unused) 847 { 848 return 0; 849 } 850 851 static int hist_entry__callchain_branch_predicted_snprintf( 852 struct hist_entry *he, char *bf, size_t size, unsigned int width) 853 { 854 u64 branch_count, predicted_count; 855 double percent = 0.0; 856 char str[32]; 857 858 callchain_branch_counts(he->callchain, &branch_count, 859 &predicted_count, NULL, NULL); 860 861 if (branch_count) 862 percent = predicted_count * 100.0 / branch_count; 863 864 snprintf(str, sizeof(str), "%.1f%%", percent); 865 return repsep_snprintf(bf, size, "%-*.*s", width, width, str); 866 } 867 868 static struct sort_entry sort_callchain_branch_predicted = { 869 .se_header = "Predicted", 870 .se_cmp = sort__callchain_branch_predicted_cmp, 871 .se_snprintf = hist_entry__callchain_branch_predicted_snprintf, 872 .se_width_idx = HISTC_CALLCHAIN_BRANCH_PREDICTED, 873 }; 874 875 /* --sort callchain_branch_abort */ 876 877 static int64_t 878 sort__callchain_branch_abort_cmp(struct hist_entry *left __maybe_unused, 879 struct hist_entry *right __maybe_unused) 880 { 881 return 0; 882 } 883 884 static int hist_entry__callchain_branch_abort_snprintf(struct hist_entry *he, 885 char *bf, size_t size, 886 unsigned int width) 887 { 888 u64 branch_count, abort_count; 889 char str[32]; 890 891 callchain_branch_counts(he->callchain, &branch_count, 892 NULL, &abort_count, NULL); 893 894 snprintf(str, sizeof(str), "%" PRId64, abort_count); 895 return repsep_snprintf(bf, size, "%-*.*s", width, width, str); 896 } 897 898 static struct sort_entry sort_callchain_branch_abort = { 899 .se_header = "Abort", 900 .se_cmp = sort__callchain_branch_abort_cmp, 901 .se_snprintf = hist_entry__callchain_branch_abort_snprintf, 902 .se_width_idx = HISTC_CALLCHAIN_BRANCH_ABORT, 903 }; 904 905 /* --sort callchain_branch_cycles */ 906 907 static int64_t 908 sort__callchain_branch_cycles_cmp(struct hist_entry *left __maybe_unused, 909 struct hist_entry *right __maybe_unused) 910 { 911 return 0; 912 } 913 914 static int hist_entry__callchain_branch_cycles_snprintf(struct hist_entry *he, 915 char *bf, size_t size, 916 unsigned int width) 917 { 918 u64 branch_count, cycles_count, cycles = 0; 919 char str[32]; 920 921 callchain_branch_counts(he->callchain, &branch_count, 922 NULL, NULL, &cycles_count); 923 924 if (branch_count) 925 cycles = cycles_count / branch_count; 926 927 snprintf(str, sizeof(str), "%" PRId64 "", cycles); 928 return repsep_snprintf(bf, size, "%-*.*s", width, width, str); 929 } 930 931 static struct sort_entry sort_callchain_branch_cycles = { 932 .se_header = "Cycles", 933 .se_cmp = sort__callchain_branch_cycles_cmp, 934 .se_snprintf = hist_entry__callchain_branch_cycles_snprintf, 935 .se_width_idx = HISTC_CALLCHAIN_BRANCH_CYCLES, 936 }; 937 938 /* --sort srcfile */ 939 940 static char no_srcfile[1]; 941 942 static char *hist_entry__get_srcfile(struct hist_entry *e) 943 { 944 char *sf, *p; 945 struct map *map = e->ms.map; 946 947 if (!map) 948 return no_srcfile; 949 950 sf = __get_srcline(map__dso(map), map__rip_2objdump(map, e->ip), 951 e->ms.sym, false, true, true, e->ip); 952 if (sf == SRCLINE_UNKNOWN) 953 return no_srcfile; 954 p = strchr(sf, ':'); 955 if (p && *sf) { 956 *p = 0; 957 return sf; 958 } 959 free(sf); 960 return no_srcfile; 961 } 962 963 static int64_t 964 sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right) 965 { 966 return sort__srcline_cmp(left, right); 967 } 968 969 static int64_t 970 sort__srcfile_collapse(struct hist_entry *left, struct hist_entry *right) 971 { 972 if (!left->srcfile) 973 left->srcfile = hist_entry__get_srcfile(left); 974 if (!right->srcfile) 975 right->srcfile = hist_entry__get_srcfile(right); 976 977 return strcmp(right->srcfile, left->srcfile); 978 } 979 980 static int64_t 981 sort__srcfile_sort(struct hist_entry *left, struct hist_entry *right) 982 { 983 return sort__srcfile_collapse(left, right); 984 } 985 986 static void sort__srcfile_init(struct hist_entry *he) 987 { 988 if (!he->srcfile) 989 he->srcfile = hist_entry__get_srcfile(he); 990 } 991 992 static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf, 993 size_t size, unsigned int width) 994 { 995 return repsep_snprintf(bf, size, "%-.*s", width, he->srcfile); 996 } 997 998 static struct sort_entry sort_srcfile = { 999 .se_header = "Source File", 1000 .se_cmp = sort__srcfile_cmp, 1001 .se_collapse = sort__srcfile_collapse, 1002 .se_sort = sort__srcfile_sort, 1003 .se_init = sort__srcfile_init, 1004 .se_snprintf = hist_entry__srcfile_snprintf, 1005 .se_width_idx = HISTC_SRCFILE, 1006 }; 1007 1008 /* --sort parent */ 1009 1010 static int64_t 1011 sort__parent_cmp(struct hist_entry *left, struct hist_entry *right) 1012 { 1013 struct symbol *sym_l = left->parent; 1014 struct symbol *sym_r = right->parent; 1015 1016 if (!sym_l || !sym_r) 1017 return cmp_null(sym_l, sym_r); 1018 1019 return strcmp(sym_r->name, sym_l->name); 1020 } 1021 1022 static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf, 1023 size_t size, unsigned int width) 1024 { 1025 return repsep_snprintf(bf, size, "%-*.*s", width, width, 1026 he->parent ? he->parent->name : "[other]"); 1027 } 1028 1029 struct sort_entry sort_parent = { 1030 .se_header = "Parent symbol", 1031 .se_cmp = sort__parent_cmp, 1032 .se_snprintf = hist_entry__parent_snprintf, 1033 .se_width_idx = HISTC_PARENT, 1034 }; 1035 1036 /* --sort cpu */ 1037 1038 static int64_t 1039 sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right) 1040 { 1041 return right->cpu - left->cpu; 1042 } 1043 1044 static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf, 1045 size_t size, unsigned int width) 1046 { 1047 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu); 1048 } 1049 1050 static struct sort_entry sort_cpu = { 1051 .se_header = "CPU", 1052 .se_cmp = sort__cpu_cmp, 1053 .se_snprintf = hist_entry__cpu_snprintf, 1054 .se_width_idx = HISTC_CPU, 1055 }; 1056 1057 /* --sort parallelism */ 1058 1059 static int64_t 1060 sort__parallelism_cmp(struct hist_entry *left, struct hist_entry *right) 1061 { 1062 return right->parallelism - left->parallelism; 1063 } 1064 1065 static int hist_entry__parallelism_filter(struct hist_entry *he, int type, const void *arg) 1066 { 1067 const unsigned long *parallelism_filter = arg; 1068 1069 if (type != HIST_FILTER__PARALLELISM) 1070 return -1; 1071 1072 return test_bit(he->parallelism, parallelism_filter); 1073 } 1074 1075 static int hist_entry__parallelism_snprintf(struct hist_entry *he, char *bf, 1076 size_t size, unsigned int width) 1077 { 1078 return repsep_snprintf(bf, size, "%*d", width, he->parallelism); 1079 } 1080 1081 static struct sort_entry sort_parallelism = { 1082 .se_header = "Parallelism", 1083 .se_cmp = sort__parallelism_cmp, 1084 .se_filter = hist_entry__parallelism_filter, 1085 .se_snprintf = hist_entry__parallelism_snprintf, 1086 .se_width_idx = HISTC_PARALLELISM, 1087 }; 1088 1089 /* --sort cgroup_id */ 1090 1091 static int64_t _sort__cgroup_dev_cmp(u64 left_dev, u64 right_dev) 1092 { 1093 return (int64_t)(right_dev - left_dev); 1094 } 1095 1096 static int64_t _sort__cgroup_inode_cmp(u64 left_ino, u64 right_ino) 1097 { 1098 return (int64_t)(right_ino - left_ino); 1099 } 1100 1101 static int64_t 1102 sort__cgroup_id_cmp(struct hist_entry *left, struct hist_entry *right) 1103 { 1104 int64_t ret; 1105 1106 ret = _sort__cgroup_dev_cmp(right->cgroup_id.dev, left->cgroup_id.dev); 1107 if (ret != 0) 1108 return ret; 1109 1110 return _sort__cgroup_inode_cmp(right->cgroup_id.ino, 1111 left->cgroup_id.ino); 1112 } 1113 1114 static int hist_entry__cgroup_id_snprintf(struct hist_entry *he, 1115 char *bf, size_t size, 1116 unsigned int width __maybe_unused) 1117 { 1118 return repsep_snprintf(bf, size, "%lu/0x%lx", he->cgroup_id.dev, 1119 he->cgroup_id.ino); 1120 } 1121 1122 static struct sort_entry sort_cgroup_id = { 1123 .se_header = "cgroup id (dev/inode)", 1124 .se_cmp = sort__cgroup_id_cmp, 1125 .se_snprintf = hist_entry__cgroup_id_snprintf, 1126 .se_width_idx = HISTC_CGROUP_ID, 1127 }; 1128 1129 /* --sort cgroup */ 1130 1131 static int64_t 1132 sort__cgroup_cmp(struct hist_entry *left, struct hist_entry *right) 1133 { 1134 return right->cgroup - left->cgroup; 1135 } 1136 1137 static int hist_entry__cgroup_snprintf(struct hist_entry *he, 1138 char *bf, size_t size, 1139 unsigned int width __maybe_unused) 1140 { 1141 const char *cgrp_name = "N/A"; 1142 1143 if (he->cgroup) { 1144 struct cgroup *cgrp = cgroup__find(maps__machine(thread__maps(he->ms.thread))->env, 1145 he->cgroup); 1146 if (cgrp != NULL) 1147 cgrp_name = cgrp->name; 1148 else 1149 cgrp_name = "unknown"; 1150 } 1151 1152 return repsep_snprintf(bf, size, "%s", cgrp_name); 1153 } 1154 1155 static struct sort_entry sort_cgroup = { 1156 .se_header = "Cgroup", 1157 .se_cmp = sort__cgroup_cmp, 1158 .se_snprintf = hist_entry__cgroup_snprintf, 1159 .se_width_idx = HISTC_CGROUP, 1160 }; 1161 1162 /* --sort socket */ 1163 1164 static int64_t 1165 sort__socket_cmp(struct hist_entry *left, struct hist_entry *right) 1166 { 1167 return right->socket - left->socket; 1168 } 1169 1170 static int hist_entry__socket_snprintf(struct hist_entry *he, char *bf, 1171 size_t size, unsigned int width) 1172 { 1173 return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket); 1174 } 1175 1176 static int hist_entry__socket_filter(struct hist_entry *he, int type, const void *arg) 1177 { 1178 int sk = *(const int *)arg; 1179 1180 if (type != HIST_FILTER__SOCKET) 1181 return -1; 1182 1183 return sk >= 0 && he->socket != sk; 1184 } 1185 1186 static struct sort_entry sort_socket = { 1187 .se_header = "Socket", 1188 .se_cmp = sort__socket_cmp, 1189 .se_snprintf = hist_entry__socket_snprintf, 1190 .se_filter = hist_entry__socket_filter, 1191 .se_width_idx = HISTC_SOCKET, 1192 }; 1193 1194 /* --sort time */ 1195 1196 static int64_t 1197 sort__time_cmp(struct hist_entry *left, struct hist_entry *right) 1198 { 1199 return right->time - left->time; 1200 } 1201 1202 static int hist_entry__time_snprintf(struct hist_entry *he, char *bf, 1203 size_t size, unsigned int width) 1204 { 1205 char he_time[32]; 1206 1207 if (symbol_conf.nanosecs) 1208 timestamp__scnprintf_nsec(he->time, he_time, 1209 sizeof(he_time)); 1210 else 1211 timestamp__scnprintf_usec(he->time, he_time, 1212 sizeof(he_time)); 1213 1214 return repsep_snprintf(bf, size, "%-.*s", width, he_time); 1215 } 1216 1217 static struct sort_entry sort_time = { 1218 .se_header = "Time", 1219 .se_cmp = sort__time_cmp, 1220 .se_snprintf = hist_entry__time_snprintf, 1221 .se_width_idx = HISTC_TIME, 1222 }; 1223 1224 /* --sort trace */ 1225 1226 #ifdef HAVE_LIBTRACEEVENT 1227 static char *get_trace_output(struct hist_entry *he) 1228 { 1229 struct trace_seq seq; 1230 struct evsel *evsel; 1231 struct tep_record rec = { 1232 .data = he->raw_data, 1233 .size = he->raw_size, 1234 }; 1235 struct tep_event *tp_format; 1236 1237 evsel = hists_to_evsel(he->hists); 1238 1239 trace_seq_init(&seq); 1240 tp_format = evsel__tp_format(evsel); 1241 if (tp_format) { 1242 if (symbol_conf.raw_trace) 1243 tep_print_fields(&seq, he->raw_data, he->raw_size, tp_format); 1244 else 1245 tep_print_event(tp_format->tep, &seq, &rec, "%s", TEP_PRINT_INFO); 1246 } 1247 1248 /* 1249 * Trim the buffer, it starts at 4KB and we're not going to 1250 * add anything more to this buffer. 1251 */ 1252 return realloc(seq.buffer, seq.len + 1); 1253 } 1254 1255 static int64_t 1256 sort__trace_cmp(struct hist_entry *left, struct hist_entry *right) 1257 { 1258 struct evsel *evsel; 1259 1260 evsel = hists_to_evsel(left->hists); 1261 if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) 1262 return 0; 1263 1264 if (left->trace_output == NULL) 1265 left->trace_output = get_trace_output(left); 1266 if (right->trace_output == NULL) 1267 right->trace_output = get_trace_output(right); 1268 1269 return strcmp(right->trace_output, left->trace_output); 1270 } 1271 1272 static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf, 1273 size_t size, unsigned int width) 1274 { 1275 struct evsel *evsel; 1276 1277 evsel = hists_to_evsel(he->hists); 1278 if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) 1279 return scnprintf(bf, size, "%-.*s", width, "N/A"); 1280 1281 if (he->trace_output == NULL) 1282 he->trace_output = get_trace_output(he); 1283 return repsep_snprintf(bf, size, "%-.*s", width, he->trace_output); 1284 } 1285 1286 static struct sort_entry sort_trace = { 1287 .se_header = "Trace output", 1288 .se_cmp = sort__trace_cmp, 1289 .se_snprintf = hist_entry__trace_snprintf, 1290 .se_width_idx = HISTC_TRACE, 1291 }; 1292 #endif /* HAVE_LIBTRACEEVENT */ 1293 1294 /* sort keys for branch stacks */ 1295 1296 static int64_t 1297 sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right) 1298 { 1299 if (!left->branch_info || !right->branch_info) 1300 return cmp_null(left->branch_info, right->branch_info); 1301 1302 return _sort__dso_cmp(left->branch_info->from.ms.map, 1303 right->branch_info->from.ms.map); 1304 } 1305 1306 static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf, 1307 size_t size, unsigned int width) 1308 { 1309 if (he->branch_info) 1310 return _hist_entry__dso_snprintf(he->branch_info->from.ms.map, 1311 bf, size, width); 1312 else 1313 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 1314 } 1315 1316 static int hist_entry__dso_from_filter(struct hist_entry *he, int type, 1317 const void *arg) 1318 { 1319 const struct dso *dso = arg; 1320 1321 if (type != HIST_FILTER__DSO) 1322 return -1; 1323 1324 return dso && (!he->branch_info || !he->branch_info->from.ms.map || 1325 map__dso(he->branch_info->from.ms.map) != dso); 1326 } 1327 1328 static int64_t 1329 sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) 1330 { 1331 if (!left->branch_info || !right->branch_info) 1332 return cmp_null(left->branch_info, right->branch_info); 1333 1334 return _sort__dso_cmp(left->branch_info->to.ms.map, 1335 right->branch_info->to.ms.map); 1336 } 1337 1338 static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf, 1339 size_t size, unsigned int width) 1340 { 1341 if (he->branch_info) 1342 return _hist_entry__dso_snprintf(he->branch_info->to.ms.map, 1343 bf, size, width); 1344 else 1345 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 1346 } 1347 1348 static int hist_entry__dso_to_filter(struct hist_entry *he, int type, 1349 const void *arg) 1350 { 1351 const struct dso *dso = arg; 1352 1353 if (type != HIST_FILTER__DSO) 1354 return -1; 1355 1356 return dso && (!he->branch_info || !he->branch_info->to.ms.map || 1357 map__dso(he->branch_info->to.ms.map) != dso); 1358 } 1359 1360 static int64_t 1361 sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right) 1362 { 1363 struct addr_map_symbol *from_l, *from_r; 1364 1365 if (!left->branch_info || !right->branch_info) 1366 return cmp_null(left->branch_info, right->branch_info); 1367 1368 from_l = &left->branch_info->from; 1369 from_r = &right->branch_info->from; 1370 1371 if (!from_l->ms.sym && !from_r->ms.sym) 1372 return _sort__addr_cmp(from_l->addr, from_r->addr); 1373 1374 return _sort__sym_cmp(from_l->ms.sym, from_r->ms.sym); 1375 } 1376 1377 static int64_t 1378 sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right) 1379 { 1380 struct addr_map_symbol *to_l, *to_r; 1381 1382 if (!left->branch_info || !right->branch_info) 1383 return cmp_null(left->branch_info, right->branch_info); 1384 1385 to_l = &left->branch_info->to; 1386 to_r = &right->branch_info->to; 1387 1388 if (!to_l->ms.sym && !to_r->ms.sym) 1389 return _sort__addr_cmp(to_l->addr, to_r->addr); 1390 1391 return _sort__sym_cmp(to_l->ms.sym, to_r->ms.sym); 1392 } 1393 1394 static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf, 1395 size_t size, unsigned int width) 1396 { 1397 if (he->branch_info) { 1398 struct addr_map_symbol *from = &he->branch_info->from; 1399 1400 return _hist_entry__sym_snprintf(&from->ms, from->al_addr, 1401 from->al_level, bf, size, width); 1402 } 1403 1404 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 1405 } 1406 1407 static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf, 1408 size_t size, unsigned int width) 1409 { 1410 if (he->branch_info) { 1411 struct addr_map_symbol *to = &he->branch_info->to; 1412 1413 return _hist_entry__sym_snprintf(&to->ms, to->al_addr, 1414 to->al_level, bf, size, width); 1415 } 1416 1417 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 1418 } 1419 1420 static int hist_entry__sym_from_filter(struct hist_entry *he, int type, 1421 const void *arg) 1422 { 1423 const char *sym = arg; 1424 1425 if (type != HIST_FILTER__SYMBOL) 1426 return -1; 1427 1428 return sym && !(he->branch_info && he->branch_info->from.ms.sym && 1429 strstr(he->branch_info->from.ms.sym->name, sym)); 1430 } 1431 1432 static int hist_entry__sym_to_filter(struct hist_entry *he, int type, 1433 const void *arg) 1434 { 1435 const char *sym = arg; 1436 1437 if (type != HIST_FILTER__SYMBOL) 1438 return -1; 1439 1440 return sym && !(he->branch_info && he->branch_info->to.ms.sym && 1441 strstr(he->branch_info->to.ms.sym->name, sym)); 1442 } 1443 1444 struct sort_entry sort_dso_from = { 1445 .se_header = "Source Shared Object", 1446 .se_cmp = sort__dso_from_cmp, 1447 .se_snprintf = hist_entry__dso_from_snprintf, 1448 .se_filter = hist_entry__dso_from_filter, 1449 .se_width_idx = HISTC_DSO_FROM, 1450 }; 1451 1452 struct sort_entry sort_dso_to = { 1453 .se_header = "Target Shared Object", 1454 .se_cmp = sort__dso_to_cmp, 1455 .se_snprintf = hist_entry__dso_to_snprintf, 1456 .se_filter = hist_entry__dso_to_filter, 1457 .se_width_idx = HISTC_DSO_TO, 1458 }; 1459 1460 struct sort_entry sort_sym_from = { 1461 .se_header = "Source Symbol", 1462 .se_cmp = sort__sym_from_cmp, 1463 .se_snprintf = hist_entry__sym_from_snprintf, 1464 .se_filter = hist_entry__sym_from_filter, 1465 .se_width_idx = HISTC_SYMBOL_FROM, 1466 }; 1467 1468 struct sort_entry sort_sym_to = { 1469 .se_header = "Target Symbol", 1470 .se_cmp = sort__sym_to_cmp, 1471 .se_snprintf = hist_entry__sym_to_snprintf, 1472 .se_filter = hist_entry__sym_to_filter, 1473 .se_width_idx = HISTC_SYMBOL_TO, 1474 }; 1475 1476 static int _hist_entry__addr_snprintf(struct map_symbol *ms, 1477 u64 ip, char level, char *bf, size_t size, 1478 unsigned int width) 1479 { 1480 struct symbol *sym = ms->sym; 1481 struct map *map = ms->map; 1482 size_t ret = 0, offs; 1483 1484 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level); 1485 if (sym && map) { 1486 if (symbol__type(sym) == STT_OBJECT) { 1487 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name); 1488 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx", 1489 ip - map__unmap_ip(map, sym->start)); 1490 } else { 1491 ret += repsep_snprintf(bf + ret, size - ret, "%.*s", 1492 width - ret, 1493 sym->name); 1494 offs = ip - sym->start; 1495 if (offs) 1496 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx", offs); 1497 } 1498 } else { 1499 size_t len = BITS_PER_LONG / 4; 1500 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", 1501 len, ip); 1502 } 1503 1504 return ret; 1505 } 1506 1507 static int hist_entry__addr_from_snprintf(struct hist_entry *he, char *bf, 1508 size_t size, unsigned int width) 1509 { 1510 if (he->branch_info) { 1511 struct addr_map_symbol *from = &he->branch_info->from; 1512 1513 return _hist_entry__addr_snprintf(&from->ms, from->al_addr, 1514 he->level, bf, size, width); 1515 } 1516 1517 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 1518 } 1519 1520 static int hist_entry__addr_to_snprintf(struct hist_entry *he, char *bf, 1521 size_t size, unsigned int width) 1522 { 1523 if (he->branch_info) { 1524 struct addr_map_symbol *to = &he->branch_info->to; 1525 1526 return _hist_entry__addr_snprintf(&to->ms, to->al_addr, 1527 he->level, bf, size, width); 1528 } 1529 1530 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 1531 } 1532 1533 static int64_t 1534 sort__addr_from_cmp(struct hist_entry *left, struct hist_entry *right) 1535 { 1536 struct addr_map_symbol *from_l; 1537 struct addr_map_symbol *from_r; 1538 int64_t ret; 1539 1540 if (!left->branch_info || !right->branch_info) 1541 return cmp_null(left->branch_info, right->branch_info); 1542 1543 from_l = &left->branch_info->from; 1544 from_r = &right->branch_info->from; 1545 1546 /* 1547 * comparing symbol address alone is not enough since it's a 1548 * relative address within a dso. 1549 */ 1550 ret = _sort__dso_cmp(from_l->ms.map, from_r->ms.map); 1551 if (ret != 0) 1552 return ret; 1553 1554 return _sort__addr_cmp(from_l->addr, from_r->addr); 1555 } 1556 1557 static int64_t 1558 sort__addr_to_cmp(struct hist_entry *left, struct hist_entry *right) 1559 { 1560 struct addr_map_symbol *to_l; 1561 struct addr_map_symbol *to_r; 1562 int64_t ret; 1563 1564 if (!left->branch_info || !right->branch_info) 1565 return cmp_null(left->branch_info, right->branch_info); 1566 1567 to_l = &left->branch_info->to; 1568 to_r = &right->branch_info->to; 1569 1570 /* 1571 * comparing symbol address alone is not enough since it's a 1572 * relative address within a dso. 1573 */ 1574 ret = _sort__dso_cmp(to_l->ms.map, to_r->ms.map); 1575 if (ret != 0) 1576 return ret; 1577 1578 return _sort__addr_cmp(to_l->addr, to_r->addr); 1579 } 1580 1581 static struct sort_entry sort_addr_from = { 1582 .se_header = "Source Address", 1583 .se_cmp = sort__addr_from_cmp, 1584 .se_snprintf = hist_entry__addr_from_snprintf, 1585 .se_filter = hist_entry__sym_from_filter, /* shared with sym_from */ 1586 .se_width_idx = HISTC_ADDR_FROM, 1587 }; 1588 1589 static struct sort_entry sort_addr_to = { 1590 .se_header = "Target Address", 1591 .se_cmp = sort__addr_to_cmp, 1592 .se_snprintf = hist_entry__addr_to_snprintf, 1593 .se_filter = hist_entry__sym_to_filter, /* shared with sym_to */ 1594 .se_width_idx = HISTC_ADDR_TO, 1595 }; 1596 1597 1598 static int64_t 1599 sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right) 1600 { 1601 unsigned char mp, p; 1602 1603 if (!left->branch_info || !right->branch_info) 1604 return cmp_null(left->branch_info, right->branch_info); 1605 1606 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred; 1607 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted; 1608 return mp || p; 1609 } 1610 1611 static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf, 1612 size_t size, unsigned int width){ 1613 static const char *out = "N/A"; 1614 1615 if (he->branch_info) { 1616 if (he->branch_info->flags.predicted) 1617 out = "N"; 1618 else if (he->branch_info->flags.mispred) 1619 out = "Y"; 1620 } 1621 1622 return repsep_snprintf(bf, size, "%-*.*s", width, width, out); 1623 } 1624 1625 static int64_t 1626 sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right) 1627 { 1628 if (!left->branch_info || !right->branch_info) 1629 return cmp_null(left->branch_info, right->branch_info); 1630 1631 return left->branch_info->flags.cycles - 1632 right->branch_info->flags.cycles; 1633 } 1634 1635 static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf, 1636 size_t size, unsigned int width) 1637 { 1638 if (!he->branch_info) 1639 return scnprintf(bf, size, "%-.*s", width, "N/A"); 1640 if (he->branch_info->flags.cycles == 0) 1641 return repsep_snprintf(bf, size, "%-*s", width, "-"); 1642 return repsep_snprintf(bf, size, "%-*hd", width, 1643 he->branch_info->flags.cycles); 1644 } 1645 1646 static struct sort_entry sort_cycles = { 1647 .se_header = "Basic Block Cycles", 1648 .se_cmp = sort__cycles_cmp, 1649 .se_snprintf = hist_entry__cycles_snprintf, 1650 .se_width_idx = HISTC_CYCLES, 1651 }; 1652 1653 /* --sort daddr_sym */ 1654 int64_t 1655 sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right) 1656 { 1657 uint64_t l = 0, r = 0; 1658 1659 if (left->mem_info) 1660 l = mem_info__daddr(left->mem_info)->addr; 1661 if (right->mem_info) 1662 r = mem_info__daddr(right->mem_info)->addr; 1663 1664 return (int64_t)(r - l); 1665 } 1666 1667 static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf, 1668 size_t size, unsigned int width) 1669 { 1670 uint64_t addr = 0; 1671 struct map_symbol *ms = NULL; 1672 1673 if (he->mem_info) { 1674 addr = mem_info__daddr(he->mem_info)->addr; 1675 ms = &mem_info__daddr(he->mem_info)->ms; 1676 } 1677 return _hist_entry__sym_snprintf(ms, addr, he->level, bf, size, width); 1678 } 1679 1680 int64_t 1681 sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right) 1682 { 1683 uint64_t l = 0, r = 0; 1684 1685 if (left->mem_info) 1686 l = mem_info__iaddr(left->mem_info)->addr; 1687 if (right->mem_info) 1688 r = mem_info__iaddr(right->mem_info)->addr; 1689 1690 return (int64_t)(r - l); 1691 } 1692 1693 static int hist_entry__iaddr_snprintf(struct hist_entry *he, char *bf, 1694 size_t size, unsigned int width) 1695 { 1696 uint64_t addr = 0; 1697 struct map_symbol *ms = NULL; 1698 1699 if (he->mem_info) { 1700 addr = mem_info__iaddr(he->mem_info)->addr; 1701 ms = &mem_info__iaddr(he->mem_info)->ms; 1702 } 1703 return _hist_entry__sym_snprintf(ms, addr, he->level, bf, size, width); 1704 } 1705 1706 static int64_t 1707 sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right) 1708 { 1709 struct map *map_l = NULL; 1710 struct map *map_r = NULL; 1711 1712 if (left->mem_info) 1713 map_l = mem_info__daddr(left->mem_info)->ms.map; 1714 if (right->mem_info) 1715 map_r = mem_info__daddr(right->mem_info)->ms.map; 1716 1717 return _sort__dso_cmp(map_l, map_r); 1718 } 1719 1720 static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf, 1721 size_t size, unsigned int width) 1722 { 1723 struct map *map = NULL; 1724 1725 if (he->mem_info) 1726 map = mem_info__daddr(he->mem_info)->ms.map; 1727 1728 return _hist_entry__dso_snprintf(map, bf, size, width); 1729 } 1730 1731 static int64_t 1732 sort__locked_cmp(struct hist_entry *left, struct hist_entry *right) 1733 { 1734 union perf_mem_data_src data_src_l; 1735 union perf_mem_data_src data_src_r; 1736 1737 if (left->mem_info) 1738 data_src_l = *mem_info__data_src(left->mem_info); 1739 else 1740 data_src_l.mem_lock = PERF_MEM_LOCK_NA; 1741 1742 if (right->mem_info) 1743 data_src_r = *mem_info__data_src(right->mem_info); 1744 else 1745 data_src_r.mem_lock = PERF_MEM_LOCK_NA; 1746 1747 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock); 1748 } 1749 1750 static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf, 1751 size_t size, unsigned int width) 1752 { 1753 char out[10]; 1754 1755 perf_mem__lck_scnprintf(out, sizeof(out), he->mem_info); 1756 return repsep_snprintf(bf, size, "%.*s", width, out); 1757 } 1758 1759 static int64_t 1760 sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right) 1761 { 1762 union perf_mem_data_src data_src_l; 1763 union perf_mem_data_src data_src_r; 1764 1765 if (left->mem_info) 1766 data_src_l = *mem_info__data_src(left->mem_info); 1767 else 1768 data_src_l.mem_dtlb = PERF_MEM_TLB_NA; 1769 1770 if (right->mem_info) 1771 data_src_r = *mem_info__data_src(right->mem_info); 1772 else 1773 data_src_r.mem_dtlb = PERF_MEM_TLB_NA; 1774 1775 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb); 1776 } 1777 1778 static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf, 1779 size_t size, unsigned int width) 1780 { 1781 char out[64]; 1782 1783 perf_mem__tlb_scnprintf(out, sizeof(out), he->mem_info); 1784 return repsep_snprintf(bf, size, "%-*s", width, out); 1785 } 1786 1787 static int64_t 1788 sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right) 1789 { 1790 union perf_mem_data_src data_src_l; 1791 union perf_mem_data_src data_src_r; 1792 1793 if (left->mem_info) 1794 data_src_l = *mem_info__data_src(left->mem_info); 1795 else 1796 data_src_l.mem_lvl = PERF_MEM_LVL_NA; 1797 1798 if (right->mem_info) 1799 data_src_r = *mem_info__data_src(right->mem_info); 1800 else 1801 data_src_r.mem_lvl = PERF_MEM_LVL_NA; 1802 1803 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl); 1804 } 1805 1806 static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf, 1807 size_t size, unsigned int width) 1808 { 1809 char out[64]; 1810 1811 perf_mem__lvl_scnprintf(out, sizeof(out), he->mem_info); 1812 return repsep_snprintf(bf, size, "%-*s", width, out); 1813 } 1814 1815 static int64_t 1816 sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right) 1817 { 1818 union perf_mem_data_src data_src_l; 1819 union perf_mem_data_src data_src_r; 1820 1821 if (left->mem_info) 1822 data_src_l = *mem_info__data_src(left->mem_info); 1823 else 1824 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA; 1825 1826 if (right->mem_info) 1827 data_src_r = *mem_info__data_src(right->mem_info); 1828 else 1829 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA; 1830 1831 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop); 1832 } 1833 1834 static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf, 1835 size_t size, unsigned int width) 1836 { 1837 char out[64]; 1838 1839 perf_mem__snp_scnprintf(out, sizeof(out), he->mem_info); 1840 return repsep_snprintf(bf, size, "%-*s", width, out); 1841 } 1842 1843 int64_t 1844 sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right) 1845 { 1846 u64 l, r; 1847 struct map *l_map, *r_map; 1848 struct dso *l_dso, *r_dso; 1849 int rc; 1850 1851 if (!left->mem_info) return -1; 1852 if (!right->mem_info) return 1; 1853 1854 /* group event types together */ 1855 if (left->cpumode > right->cpumode) return -1; 1856 if (left->cpumode < right->cpumode) return 1; 1857 1858 l_map = mem_info__daddr(left->mem_info)->ms.map; 1859 r_map = mem_info__daddr(right->mem_info)->ms.map; 1860 1861 /* if both are NULL, jump to sort on al_addr instead */ 1862 if (!l_map && !r_map) 1863 goto addr; 1864 1865 if (!l_map) return -1; 1866 if (!r_map) return 1; 1867 1868 l_dso = map__dso(l_map); 1869 r_dso = map__dso(r_map); 1870 rc = dso__cmp_id(l_dso, r_dso); 1871 if (rc) 1872 return rc; 1873 /* 1874 * Addresses with no major/minor numbers or build ID are assumed to be 1875 * anonymous in userspace. Sort those on pid then address. 1876 * 1877 * The kernel and non-zero major/minor mapped areas are 1878 * assumed to be unity mapped. Sort those on address. 1879 */ 1880 if (left->cpumode != PERF_RECORD_MISC_KERNEL && (map__flags(l_map) & MAP_SHARED) == 0) { 1881 const struct dso_id *dso_id = dso__id_const(l_dso); 1882 1883 if (!dso_id->mmap2_valid) 1884 dso_id = dso__id_const(r_dso); 1885 1886 if (!build_id__is_defined(&dso_id->build_id) && 1887 (!dso_id->mmap2_valid || (dso_id->maj == 0 && dso_id->min == 0))) { 1888 /* userspace anonymous */ 1889 1890 if (thread__pid(left->thread) > thread__pid(right->thread)) 1891 return -1; 1892 if (thread__pid(left->thread) < thread__pid(right->thread)) 1893 return 1; 1894 } 1895 } 1896 1897 addr: 1898 /* al_addr does all the right addr - start + offset calculations */ 1899 l = cl_address(mem_info__daddr(left->mem_info)->al_addr, chk_double_cl); 1900 r = cl_address(mem_info__daddr(right->mem_info)->al_addr, chk_double_cl); 1901 1902 if (l > r) return -1; 1903 if (l < r) return 1; 1904 1905 return 0; 1906 } 1907 1908 static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf, 1909 size_t size, unsigned int width) 1910 { 1911 1912 uint64_t addr = 0; 1913 struct map_symbol *ms = NULL; 1914 char level = he->level; 1915 1916 if (he->mem_info) { 1917 struct map *map = mem_info__daddr(he->mem_info)->ms.map; 1918 struct dso *dso = map ? map__dso(map) : NULL; 1919 const struct dso_id *dso_id = dso ? dso__id_const(dso) : &dso_id_empty; 1920 1921 addr = cl_address(mem_info__daddr(he->mem_info)->al_addr, chk_double_cl); 1922 ms = &mem_info__daddr(he->mem_info)->ms; 1923 1924 /* print [s] for shared data mmaps */ 1925 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) && 1926 map && !(map__prot(map) & PROT_EXEC) && 1927 (map__flags(map) & MAP_SHARED) && 1928 (!dso_id->mmap2_valid || (dso_id->maj == 0 && dso_id->min == 0))) 1929 level = 's'; 1930 else if (!map) 1931 level = 'X'; 1932 } 1933 return _hist_entry__sym_snprintf(ms, addr, level, bf, size, width); 1934 } 1935 1936 static struct sort_entry sort_mispredict = { 1937 .se_header = "Branch Mispredicted", 1938 .se_cmp = sort__mispredict_cmp, 1939 .se_snprintf = hist_entry__mispredict_snprintf, 1940 .se_width_idx = HISTC_MISPREDICT, 1941 }; 1942 1943 static int64_t 1944 sort__weight_cmp(struct hist_entry *left, struct hist_entry *right) 1945 { 1946 return left->weight - right->weight; 1947 } 1948 1949 static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf, 1950 size_t size, unsigned int width) 1951 { 1952 return repsep_snprintf(bf, size, "%-*llu", width, he->weight); 1953 } 1954 1955 static struct sort_entry sort_local_weight = { 1956 .se_header = "Local Weight", 1957 .se_cmp = sort__weight_cmp, 1958 .se_snprintf = hist_entry__local_weight_snprintf, 1959 .se_width_idx = HISTC_LOCAL_WEIGHT, 1960 }; 1961 1962 static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf, 1963 size_t size, unsigned int width) 1964 { 1965 return repsep_snprintf(bf, size, "%-*llu", width, 1966 he->weight * he->stat.nr_events); 1967 } 1968 1969 static struct sort_entry sort_global_weight = { 1970 .se_header = "Weight", 1971 .se_cmp = sort__weight_cmp, 1972 .se_snprintf = hist_entry__global_weight_snprintf, 1973 .se_width_idx = HISTC_GLOBAL_WEIGHT, 1974 }; 1975 1976 static int64_t 1977 sort__ins_lat_cmp(struct hist_entry *left, struct hist_entry *right) 1978 { 1979 return left->ins_lat - right->ins_lat; 1980 } 1981 1982 static int hist_entry__local_ins_lat_snprintf(struct hist_entry *he, char *bf, 1983 size_t size, unsigned int width) 1984 { 1985 return repsep_snprintf(bf, size, "%-*u", width, he->ins_lat); 1986 } 1987 1988 static struct sort_entry sort_local_ins_lat = { 1989 .se_header = "Local INSTR Latency", 1990 .se_cmp = sort__ins_lat_cmp, 1991 .se_snprintf = hist_entry__local_ins_lat_snprintf, 1992 .se_width_idx = HISTC_LOCAL_INS_LAT, 1993 }; 1994 1995 static int hist_entry__global_ins_lat_snprintf(struct hist_entry *he, char *bf, 1996 size_t size, unsigned int width) 1997 { 1998 return repsep_snprintf(bf, size, "%-*u", width, 1999 he->ins_lat * he->stat.nr_events); 2000 } 2001 2002 static struct sort_entry sort_global_ins_lat = { 2003 .se_header = "INSTR Latency", 2004 .se_cmp = sort__ins_lat_cmp, 2005 .se_snprintf = hist_entry__global_ins_lat_snprintf, 2006 .se_width_idx = HISTC_GLOBAL_INS_LAT, 2007 }; 2008 2009 static int64_t 2010 sort__p_stage_cyc_cmp(struct hist_entry *left, struct hist_entry *right) 2011 { 2012 return left->weight3 - right->weight3; 2013 } 2014 2015 static int hist_entry__global_p_stage_cyc_snprintf(struct hist_entry *he, char *bf, 2016 size_t size, unsigned int width) 2017 { 2018 return repsep_snprintf(bf, size, "%-*u", width, he->weight3 * he->stat.nr_events); 2019 } 2020 2021 2022 static int hist_entry__p_stage_cyc_snprintf(struct hist_entry *he, char *bf, 2023 size_t size, unsigned int width) 2024 { 2025 return repsep_snprintf(bf, size, "%-*u", width, he->weight3); 2026 } 2027 2028 static struct sort_entry sort_local_p_stage_cyc = { 2029 .se_header = "Local Pipeline Stage Cycle", 2030 .se_cmp = sort__p_stage_cyc_cmp, 2031 .se_snprintf = hist_entry__p_stage_cyc_snprintf, 2032 .se_width_idx = HISTC_LOCAL_P_STAGE_CYC, 2033 }; 2034 2035 static struct sort_entry sort_global_p_stage_cyc = { 2036 .se_header = "Pipeline Stage Cycle", 2037 .se_cmp = sort__p_stage_cyc_cmp, 2038 .se_snprintf = hist_entry__global_p_stage_cyc_snprintf, 2039 .se_width_idx = HISTC_GLOBAL_P_STAGE_CYC, 2040 }; 2041 2042 static struct sort_entry sort_mem_daddr_sym = { 2043 .se_header = "Data Symbol", 2044 .se_cmp = sort__daddr_cmp, 2045 .se_snprintf = hist_entry__daddr_snprintf, 2046 .se_width_idx = HISTC_MEM_DADDR_SYMBOL, 2047 }; 2048 2049 static struct sort_entry sort_mem_iaddr_sym = { 2050 .se_header = "Code Symbol", 2051 .se_cmp = sort__iaddr_cmp, 2052 .se_snprintf = hist_entry__iaddr_snprintf, 2053 .se_width_idx = HISTC_MEM_IADDR_SYMBOL, 2054 }; 2055 2056 static struct sort_entry sort_mem_daddr_dso = { 2057 .se_header = "Data Object", 2058 .se_cmp = sort__dso_daddr_cmp, 2059 .se_snprintf = hist_entry__dso_daddr_snprintf, 2060 .se_width_idx = HISTC_MEM_DADDR_DSO, 2061 }; 2062 2063 static struct sort_entry sort_mem_locked = { 2064 .se_header = "Locked", 2065 .se_cmp = sort__locked_cmp, 2066 .se_snprintf = hist_entry__locked_snprintf, 2067 .se_width_idx = HISTC_MEM_LOCKED, 2068 }; 2069 2070 static struct sort_entry sort_mem_tlb = { 2071 .se_header = "TLB access", 2072 .se_cmp = sort__tlb_cmp, 2073 .se_snprintf = hist_entry__tlb_snprintf, 2074 .se_width_idx = HISTC_MEM_TLB, 2075 }; 2076 2077 static struct sort_entry sort_mem_lvl = { 2078 .se_header = "Memory access", 2079 .se_cmp = sort__lvl_cmp, 2080 .se_snprintf = hist_entry__lvl_snprintf, 2081 .se_width_idx = HISTC_MEM_LVL, 2082 }; 2083 2084 static struct sort_entry sort_mem_snoop = { 2085 .se_header = "Snoop", 2086 .se_cmp = sort__snoop_cmp, 2087 .se_snprintf = hist_entry__snoop_snprintf, 2088 .se_width_idx = HISTC_MEM_SNOOP, 2089 }; 2090 2091 static struct sort_entry sort_mem_dcacheline = { 2092 .se_header = "Data Cacheline", 2093 .se_cmp = sort__dcacheline_cmp, 2094 .se_snprintf = hist_entry__dcacheline_snprintf, 2095 .se_width_idx = HISTC_MEM_DCACHELINE, 2096 }; 2097 2098 static int64_t 2099 sort__blocked_cmp(struct hist_entry *left, struct hist_entry *right) 2100 { 2101 union perf_mem_data_src data_src_l; 2102 union perf_mem_data_src data_src_r; 2103 2104 if (left->mem_info) 2105 data_src_l = *mem_info__data_src(left->mem_info); 2106 else 2107 data_src_l.mem_blk = PERF_MEM_BLK_NA; 2108 2109 if (right->mem_info) 2110 data_src_r = *mem_info__data_src(right->mem_info); 2111 else 2112 data_src_r.mem_blk = PERF_MEM_BLK_NA; 2113 2114 return (int64_t)(data_src_r.mem_blk - data_src_l.mem_blk); 2115 } 2116 2117 static int hist_entry__blocked_snprintf(struct hist_entry *he, char *bf, 2118 size_t size, unsigned int width) 2119 { 2120 char out[16]; 2121 2122 perf_mem__blk_scnprintf(out, sizeof(out), he->mem_info); 2123 return repsep_snprintf(bf, size, "%.*s", width, out); 2124 } 2125 2126 static struct sort_entry sort_mem_blocked = { 2127 .se_header = "Blocked", 2128 .se_cmp = sort__blocked_cmp, 2129 .se_snprintf = hist_entry__blocked_snprintf, 2130 .se_width_idx = HISTC_MEM_BLOCKED, 2131 }; 2132 2133 static int64_t 2134 sort__phys_daddr_cmp(struct hist_entry *left, struct hist_entry *right) 2135 { 2136 uint64_t l = 0, r = 0; 2137 2138 if (left->mem_info) 2139 l = mem_info__daddr(left->mem_info)->phys_addr; 2140 if (right->mem_info) 2141 r = mem_info__daddr(right->mem_info)->phys_addr; 2142 2143 return (int64_t)(r - l); 2144 } 2145 2146 static int hist_entry__phys_daddr_snprintf(struct hist_entry *he, char *bf, 2147 size_t size, unsigned int width) 2148 { 2149 uint64_t addr = 0; 2150 size_t ret = 0; 2151 size_t len = BITS_PER_LONG / 4; 2152 2153 addr = mem_info__daddr(he->mem_info)->phys_addr; 2154 2155 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", he->level); 2156 2157 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", len, addr); 2158 2159 ret += repsep_snprintf(bf + ret, size - ret, "%-*s", width - ret, ""); 2160 2161 if (ret > width) 2162 bf[width] = '\0'; 2163 2164 return width; 2165 } 2166 2167 static struct sort_entry sort_mem_phys_daddr = { 2168 .se_header = "Data Physical Address", 2169 .se_cmp = sort__phys_daddr_cmp, 2170 .se_snprintf = hist_entry__phys_daddr_snprintf, 2171 .se_width_idx = HISTC_MEM_PHYS_DADDR, 2172 }; 2173 2174 static int64_t 2175 sort__data_page_size_cmp(struct hist_entry *left, struct hist_entry *right) 2176 { 2177 uint64_t l = 0, r = 0; 2178 2179 if (left->mem_info) 2180 l = mem_info__daddr(left->mem_info)->data_page_size; 2181 if (right->mem_info) 2182 r = mem_info__daddr(right->mem_info)->data_page_size; 2183 2184 return (int64_t)(r - l); 2185 } 2186 2187 static int hist_entry__data_page_size_snprintf(struct hist_entry *he, char *bf, 2188 size_t size, unsigned int width) 2189 { 2190 char str[PAGE_SIZE_NAME_LEN]; 2191 2192 return repsep_snprintf(bf, size, "%-*s", width, 2193 get_page_size_name(mem_info__daddr(he->mem_info)->data_page_size, str)); 2194 } 2195 2196 static struct sort_entry sort_mem_data_page_size = { 2197 .se_header = "Data Page Size", 2198 .se_cmp = sort__data_page_size_cmp, 2199 .se_snprintf = hist_entry__data_page_size_snprintf, 2200 .se_width_idx = HISTC_MEM_DATA_PAGE_SIZE, 2201 }; 2202 2203 static int64_t 2204 sort__code_page_size_cmp(struct hist_entry *left, struct hist_entry *right) 2205 { 2206 uint64_t l = left->code_page_size; 2207 uint64_t r = right->code_page_size; 2208 2209 return (int64_t)(r - l); 2210 } 2211 2212 static int hist_entry__code_page_size_snprintf(struct hist_entry *he, char *bf, 2213 size_t size, unsigned int width) 2214 { 2215 char str[PAGE_SIZE_NAME_LEN]; 2216 2217 return repsep_snprintf(bf, size, "%-*s", width, 2218 get_page_size_name(he->code_page_size, str)); 2219 } 2220 2221 static struct sort_entry sort_code_page_size = { 2222 .se_header = "Code Page Size", 2223 .se_cmp = sort__code_page_size_cmp, 2224 .se_snprintf = hist_entry__code_page_size_snprintf, 2225 .se_width_idx = HISTC_CODE_PAGE_SIZE, 2226 }; 2227 2228 static int64_t 2229 sort__abort_cmp(struct hist_entry *left, struct hist_entry *right) 2230 { 2231 if (!left->branch_info || !right->branch_info) 2232 return cmp_null(left->branch_info, right->branch_info); 2233 2234 return left->branch_info->flags.abort != 2235 right->branch_info->flags.abort; 2236 } 2237 2238 static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf, 2239 size_t size, unsigned int width) 2240 { 2241 static const char *out = "N/A"; 2242 2243 if (he->branch_info) { 2244 if (he->branch_info->flags.abort) 2245 out = "A"; 2246 else 2247 out = "."; 2248 } 2249 2250 return repsep_snprintf(bf, size, "%-*s", width, out); 2251 } 2252 2253 static struct sort_entry sort_abort = { 2254 .se_header = "Transaction abort", 2255 .se_cmp = sort__abort_cmp, 2256 .se_snprintf = hist_entry__abort_snprintf, 2257 .se_width_idx = HISTC_ABORT, 2258 }; 2259 2260 static int64_t 2261 sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right) 2262 { 2263 if (!left->branch_info || !right->branch_info) 2264 return cmp_null(left->branch_info, right->branch_info); 2265 2266 return left->branch_info->flags.in_tx != 2267 right->branch_info->flags.in_tx; 2268 } 2269 2270 static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf, 2271 size_t size, unsigned int width) 2272 { 2273 static const char *out = "N/A"; 2274 2275 if (he->branch_info) { 2276 if (he->branch_info->flags.in_tx) 2277 out = "T"; 2278 else 2279 out = "."; 2280 } 2281 2282 return repsep_snprintf(bf, size, "%-*s", width, out); 2283 } 2284 2285 static struct sort_entry sort_in_tx = { 2286 .se_header = "Branch in transaction", 2287 .se_cmp = sort__in_tx_cmp, 2288 .se_snprintf = hist_entry__in_tx_snprintf, 2289 .se_width_idx = HISTC_IN_TX, 2290 }; 2291 2292 static int64_t 2293 sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right) 2294 { 2295 return left->transaction - right->transaction; 2296 } 2297 2298 static inline char *add_str(char *p, const char *str) 2299 { 2300 strcpy(p, str); 2301 return p + strlen(str); 2302 } 2303 2304 static struct txbit { 2305 unsigned flag; 2306 const char *name; 2307 int skip_for_len; 2308 } txbits[] = { 2309 { PERF_TXN_ELISION, "EL ", 0 }, 2310 { PERF_TXN_TRANSACTION, "TX ", 1 }, 2311 { PERF_TXN_SYNC, "SYNC ", 1 }, 2312 { PERF_TXN_ASYNC, "ASYNC ", 0 }, 2313 { PERF_TXN_RETRY, "RETRY ", 0 }, 2314 { PERF_TXN_CONFLICT, "CON ", 0 }, 2315 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 }, 2316 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 }, 2317 { 0, NULL, 0 } 2318 }; 2319 2320 int hist_entry__transaction_len(void) 2321 { 2322 int i; 2323 int len = 0; 2324 2325 for (i = 0; txbits[i].name; i++) { 2326 if (!txbits[i].skip_for_len) 2327 len += strlen(txbits[i].name); 2328 } 2329 len += 4; /* :XX<space> */ 2330 return len; 2331 } 2332 2333 static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf, 2334 size_t size, unsigned int width) 2335 { 2336 u64 t = he->transaction; 2337 char buf[128]; 2338 char *p = buf; 2339 int i; 2340 2341 buf[0] = 0; 2342 for (i = 0; txbits[i].name; i++) 2343 if (txbits[i].flag & t) 2344 p = add_str(p, txbits[i].name); 2345 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC))) 2346 p = add_str(p, "NEITHER "); 2347 if (t & PERF_TXN_ABORT_MASK) { 2348 sprintf(p, ":%" PRIx64, 2349 (t & PERF_TXN_ABORT_MASK) >> 2350 PERF_TXN_ABORT_SHIFT); 2351 p += strlen(p); 2352 } 2353 2354 return repsep_snprintf(bf, size, "%-*s", width, buf); 2355 } 2356 2357 static struct sort_entry sort_transaction = { 2358 .se_header = "Transaction ", 2359 .se_cmp = sort__transaction_cmp, 2360 .se_snprintf = hist_entry__transaction_snprintf, 2361 .se_width_idx = HISTC_TRANSACTION, 2362 }; 2363 2364 /* --sort symbol_size */ 2365 2366 static int64_t _sort__sym_size_cmp(struct symbol *sym_l, struct symbol *sym_r) 2367 { 2368 int64_t size_l = sym_l != NULL ? symbol__size(sym_l) : 0; 2369 int64_t size_r = sym_r != NULL ? symbol__size(sym_r) : 0; 2370 2371 return size_l < size_r ? -1 : 2372 size_l == size_r ? 0 : 1; 2373 } 2374 2375 static int64_t 2376 sort__sym_size_cmp(struct hist_entry *left, struct hist_entry *right) 2377 { 2378 return _sort__sym_size_cmp(right->ms.sym, left->ms.sym); 2379 } 2380 2381 static int _hist_entry__sym_size_snprintf(struct symbol *sym, char *bf, 2382 size_t bf_size, unsigned int width) 2383 { 2384 if (sym) 2385 return repsep_snprintf(bf, bf_size, "%*d", width, symbol__size(sym)); 2386 2387 return repsep_snprintf(bf, bf_size, "%*s", width, "unknown"); 2388 } 2389 2390 static int hist_entry__sym_size_snprintf(struct hist_entry *he, char *bf, 2391 size_t size, unsigned int width) 2392 { 2393 return _hist_entry__sym_size_snprintf(he->ms.sym, bf, size, width); 2394 } 2395 2396 static struct sort_entry sort_sym_size = { 2397 .se_header = "Symbol size", 2398 .se_cmp = sort__sym_size_cmp, 2399 .se_snprintf = hist_entry__sym_size_snprintf, 2400 .se_width_idx = HISTC_SYM_SIZE, 2401 }; 2402 2403 /* --sort dso_size */ 2404 2405 static int64_t _sort__dso_size_cmp(struct map *map_l, struct map *map_r) 2406 { 2407 int64_t size_l = map_l != NULL ? map__size(map_l) : 0; 2408 int64_t size_r = map_r != NULL ? map__size(map_r) : 0; 2409 2410 return size_l < size_r ? -1 : 2411 size_l == size_r ? 0 : 1; 2412 } 2413 2414 static int64_t 2415 sort__dso_size_cmp(struct hist_entry *left, struct hist_entry *right) 2416 { 2417 return _sort__dso_size_cmp(right->ms.map, left->ms.map); 2418 } 2419 2420 static int _hist_entry__dso_size_snprintf(struct map *map, char *bf, 2421 size_t bf_size, unsigned int width) 2422 { 2423 if (map && map__dso(map)) 2424 return repsep_snprintf(bf, bf_size, "%*d", width, map__size(map)); 2425 2426 return repsep_snprintf(bf, bf_size, "%*s", width, "unknown"); 2427 } 2428 2429 static int hist_entry__dso_size_snprintf(struct hist_entry *he, char *bf, 2430 size_t size, unsigned int width) 2431 { 2432 return _hist_entry__dso_size_snprintf(he->ms.map, bf, size, width); 2433 } 2434 2435 static struct sort_entry sort_dso_size = { 2436 .se_header = "DSO size", 2437 .se_cmp = sort__dso_size_cmp, 2438 .se_snprintf = hist_entry__dso_size_snprintf, 2439 .se_width_idx = HISTC_DSO_SIZE, 2440 }; 2441 2442 /* --sort addr */ 2443 2444 static int64_t 2445 sort__addr_cmp(struct hist_entry *left, struct hist_entry *right) 2446 { 2447 u64 left_ip = left->ip; 2448 u64 right_ip = right->ip; 2449 struct map *left_map = left->ms.map; 2450 struct map *right_map = right->ms.map; 2451 2452 if (left_map) 2453 left_ip = map__unmap_ip(left_map, left_ip); 2454 if (right_map) 2455 right_ip = map__unmap_ip(right_map, right_ip); 2456 2457 return _sort__addr_cmp(left_ip, right_ip); 2458 } 2459 2460 static int hist_entry__addr_snprintf(struct hist_entry *he, char *bf, 2461 size_t size, unsigned int width) 2462 { 2463 u64 ip = he->ip; 2464 struct map *map = he->ms.map; 2465 2466 if (map) 2467 ip = map__unmap_ip(map, ip); 2468 2469 return repsep_snprintf(bf, size, "%-#*llx", width, ip); 2470 } 2471 2472 static struct sort_entry sort_addr = { 2473 .se_header = "Address", 2474 .se_cmp = sort__addr_cmp, 2475 .se_snprintf = hist_entry__addr_snprintf, 2476 .se_width_idx = HISTC_ADDR, 2477 }; 2478 2479 /* --sort type */ 2480 2481 struct annotated_data_type unknown_type = { 2482 .self = { 2483 .type_name = (char *)"(unknown)", 2484 .children = LIST_HEAD_INIT(unknown_type.self.children), 2485 }, 2486 }; 2487 2488 static int64_t 2489 sort__type_cmp(struct hist_entry *left, struct hist_entry *right) 2490 { 2491 return sort__addr_cmp(left, right); 2492 } 2493 2494 static void sort__type_init(struct hist_entry *he) 2495 { 2496 if (he->mem_type) 2497 return; 2498 2499 he->mem_type = hist_entry__get_data_type(he); 2500 if (he->mem_type == NULL) { 2501 he->mem_type = &unknown_type; 2502 he->mem_type_off = 0; 2503 } 2504 } 2505 2506 static int64_t 2507 sort__type_collapse(struct hist_entry *left, struct hist_entry *right) 2508 { 2509 struct annotated_data_type *left_type = left->mem_type; 2510 struct annotated_data_type *right_type = right->mem_type; 2511 2512 if (!left_type) { 2513 sort__type_init(left); 2514 left_type = left->mem_type; 2515 } 2516 2517 if (!right_type) { 2518 sort__type_init(right); 2519 right_type = right->mem_type; 2520 } 2521 2522 return strcmp(left_type->self.type_name, right_type->self.type_name); 2523 } 2524 2525 static int64_t 2526 sort__type_sort(struct hist_entry *left, struct hist_entry *right) 2527 { 2528 return sort__type_collapse(left, right); 2529 } 2530 2531 static int hist_entry__type_snprintf(struct hist_entry *he, char *bf, 2532 size_t size, unsigned int width) 2533 { 2534 return repsep_snprintf(bf, size, "%-*s", width, he->mem_type->self.type_name); 2535 } 2536 2537 struct sort_entry sort_type = { 2538 .se_header = "Data Type", 2539 .se_cmp = sort__type_cmp, 2540 .se_collapse = sort__type_collapse, 2541 .se_sort = sort__type_sort, 2542 .se_init = sort__type_init, 2543 .se_snprintf = hist_entry__type_snprintf, 2544 .se_width_idx = HISTC_TYPE, 2545 }; 2546 2547 /* --sort typeoff */ 2548 2549 static int64_t 2550 sort__typeoff_sort(struct hist_entry *left, struct hist_entry *right) 2551 { 2552 struct annotated_data_type *left_type = left->mem_type; 2553 struct annotated_data_type *right_type = right->mem_type; 2554 int64_t ret; 2555 2556 if (!left_type) { 2557 sort__type_init(left); 2558 left_type = left->mem_type; 2559 } 2560 2561 if (!right_type) { 2562 sort__type_init(right); 2563 right_type = right->mem_type; 2564 } 2565 2566 ret = strcmp(left_type->self.type_name, right_type->self.type_name); 2567 if (ret) 2568 return ret; 2569 return left->mem_type_off - right->mem_type_off; 2570 } 2571 2572 static int hist_entry__typeoff_snprintf(struct hist_entry *he, char *bf, 2573 size_t size, unsigned int width __maybe_unused) 2574 { 2575 struct annotated_data_type *he_type = he->mem_type; 2576 char buf[4096]; 2577 2578 if (he_type == &unknown_type || he_type == &stackop_type || 2579 he_type == &canary_type) 2580 return repsep_snprintf(bf, size, "%s", he_type->self.type_name); 2581 2582 if (!annotated_data_type__get_member_name(he_type, buf, sizeof(buf), 2583 he->mem_type_off)) 2584 scnprintf(buf, sizeof(buf), "no field"); 2585 2586 return repsep_snprintf(bf, size, "%s +%#x (%s)", he_type->self.type_name, 2587 he->mem_type_off, buf); 2588 } 2589 2590 static struct sort_entry sort_type_offset = { 2591 .se_header = "Data Type Offset", 2592 .se_cmp = sort__type_cmp, 2593 .se_collapse = sort__typeoff_sort, 2594 .se_sort = sort__typeoff_sort, 2595 .se_init = sort__type_init, 2596 .se_snprintf = hist_entry__typeoff_snprintf, 2597 .se_width_idx = HISTC_TYPE_OFFSET, 2598 }; 2599 2600 /* --sort typecln */ 2601 2602 static int 2603 hist_entry__cln_size(struct hist_entry *he) 2604 { 2605 int ret = 0; 2606 2607 if (he && he->hists) { 2608 struct evsel *evsel = hists_to_evsel(he->hists); 2609 2610 if (evsel) { 2611 struct perf_session *session = evsel__session(evsel); 2612 2613 ret = session->header.env.cln_size; 2614 } 2615 } 2616 2617 if (ret < 1) 2618 ret = DEFAULT_CACHELINE_SIZE; // avoid div/0 later 2619 2620 return ret; 2621 } 2622 2623 static int64_t 2624 sort__typecln_sort(struct hist_entry *left, struct hist_entry *right) 2625 { 2626 struct annotated_data_type *left_type = left->mem_type; 2627 struct annotated_data_type *right_type = right->mem_type; 2628 int64_t left_cln, right_cln; 2629 int64_t cln_size_left = hist_entry__cln_size(left); 2630 int64_t cln_size_right = hist_entry__cln_size(right); 2631 int64_t ret; 2632 2633 if (!left_type) { 2634 sort__type_init(left); 2635 left_type = left->mem_type; 2636 } 2637 2638 if (!right_type) { 2639 sort__type_init(right); 2640 right_type = right->mem_type; 2641 } 2642 2643 ret = strcmp(left_type->self.type_name, right_type->self.type_name); 2644 if (ret) 2645 return ret; 2646 2647 left_cln = left->mem_type_off / cln_size_left; 2648 right_cln = right->mem_type_off / cln_size_right; 2649 return left_cln - right_cln; 2650 } 2651 2652 static int hist_entry__typecln_snprintf(struct hist_entry *he, char *bf, 2653 size_t size, unsigned int width __maybe_unused) 2654 { 2655 struct annotated_data_type *he_type = he->mem_type; 2656 int cln_size = hist_entry__cln_size(he); 2657 2658 return repsep_snprintf(bf, size, "%s: cache-line %d", he_type->self.type_name, 2659 he->mem_type_off / cln_size); 2660 } 2661 2662 static struct sort_entry sort_type_cacheline = { 2663 .se_header = "Data Type Cacheline", 2664 .se_cmp = sort__type_cmp, 2665 .se_collapse = sort__typecln_sort, 2666 .se_sort = sort__typecln_sort, 2667 .se_init = sort__type_init, 2668 .se_snprintf = hist_entry__typecln_snprintf, 2669 .se_width_idx = HISTC_TYPE_CACHELINE, 2670 }; 2671 2672 2673 struct sort_dimension { 2674 const char *name; 2675 struct sort_entry *entry; 2676 int taken; 2677 }; 2678 2679 static int arch_support_sort_key(const char *sort_key, struct perf_env *env) 2680 { 2681 uint16_t e_machine = perf_env__e_machine(env, /*e_eflags=*/NULL); 2682 2683 if (e_machine == EM_X86_64 || e_machine == EM_386 || e_machine == EM_PPC64 || 2684 e_machine == EM_PPC) { 2685 if (!strcmp(sort_key, "p_stage_cyc")) 2686 return 1; 2687 if (!strcmp(sort_key, "local_p_stage_cyc")) 2688 return 1; 2689 } 2690 return 0; 2691 } 2692 2693 static const char *arch_perf_header_entry(const char *se_header, struct perf_env *env) 2694 { 2695 uint16_t e_machine = perf_env__e_machine(env, /*e_eflags=*/NULL); 2696 2697 if (e_machine == EM_X86_64 || e_machine == EM_386) { 2698 if (!strcmp(se_header, "Local Pipeline Stage Cycle")) 2699 return "Local Retire Latency"; 2700 else if (!strcmp(se_header, "Pipeline Stage Cycle")) 2701 return "Retire Latency"; 2702 } else if (e_machine == EM_PPC64 || e_machine == EM_PPC) { 2703 if (!strcmp(se_header, "Local INSTR Latency")) 2704 return "Finish Cyc"; 2705 else if (!strcmp(se_header, "INSTR Latency")) 2706 return "Global Finish_cyc"; 2707 else if (!strcmp(se_header, "Local Pipeline Stage Cycle")) 2708 return "Dispatch Cyc"; 2709 else if (!strcmp(se_header, "Pipeline Stage Cycle")) 2710 return "Global Dispatch_cyc"; 2711 } 2712 return se_header; 2713 } 2714 2715 static void sort_dimension_add_dynamic_header(struct sort_dimension *sd, struct perf_env *env) 2716 { 2717 sd->entry->se_header = arch_perf_header_entry(sd->entry->se_header, env); 2718 } 2719 2720 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) } 2721 2722 static struct sort_dimension common_sort_dimensions[] = { 2723 DIM(SORT_PID, "pid", sort_thread), 2724 DIM(SORT_TGID, "tgid", sort_tgid), 2725 DIM(SORT_COMM, "comm", sort_comm), 2726 DIM(SORT_COMM_NODIGIT, "comm_nodigit", sort_comm_nodigit), 2727 DIM(SORT_DSO, "dso", sort_dso), 2728 DIM(SORT_SYM, "symbol", sort_sym), 2729 DIM(SORT_PARENT, "parent", sort_parent), 2730 DIM(SORT_CPU, "cpu", sort_cpu), 2731 DIM(SORT_SOCKET, "socket", sort_socket), 2732 DIM(SORT_SRCLINE, "srcline", sort_srcline), 2733 DIM(SORT_SRCFILE, "srcfile", sort_srcfile), 2734 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), 2735 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), 2736 DIM(SORT_TRANSACTION, "transaction", sort_transaction), 2737 #ifdef HAVE_LIBTRACEEVENT 2738 DIM(SORT_TRACE, "trace", sort_trace), 2739 #endif 2740 DIM(SORT_SYM_SIZE, "symbol_size", sort_sym_size), 2741 DIM(SORT_DSO_SIZE, "dso_size", sort_dso_size), 2742 DIM(SORT_CGROUP, "cgroup", sort_cgroup), 2743 DIM(SORT_CGROUP_ID, "cgroup_id", sort_cgroup_id), 2744 DIM(SORT_SYM_IPC_NULL, "ipc_null", sort_sym_ipc_null), 2745 DIM(SORT_TIME, "time", sort_time), 2746 DIM(SORT_CODE_PAGE_SIZE, "code_page_size", sort_code_page_size), 2747 DIM(SORT_LOCAL_INS_LAT, "local_ins_lat", sort_local_ins_lat), 2748 DIM(SORT_GLOBAL_INS_LAT, "ins_lat", sort_global_ins_lat), 2749 DIM(SORT_LOCAL_PIPELINE_STAGE_CYC, "local_p_stage_cyc", sort_local_p_stage_cyc), 2750 DIM(SORT_GLOBAL_PIPELINE_STAGE_CYC, "p_stage_cyc", sort_global_p_stage_cyc), 2751 DIM(SORT_ADDR, "addr", sort_addr), 2752 DIM(SORT_LOCAL_RETIRE_LAT, "local_retire_lat", sort_local_p_stage_cyc), 2753 DIM(SORT_GLOBAL_RETIRE_LAT, "retire_lat", sort_global_p_stage_cyc), 2754 DIM(SORT_SIMD, "simd", sort_simd), 2755 DIM(SORT_ANNOTATE_DATA_TYPE, "type", sort_type), 2756 DIM(SORT_ANNOTATE_DATA_TYPE_OFFSET, "typeoff", sort_type_offset), 2757 DIM(SORT_SYM_OFFSET, "symoff", sort_sym_offset), 2758 DIM(SORT_ANNOTATE_DATA_TYPE_CACHELINE, "typecln", sort_type_cacheline), 2759 DIM(SORT_PARALLELISM, "parallelism", sort_parallelism), 2760 }; 2761 2762 #undef DIM 2763 2764 #define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) } 2765 2766 static struct sort_dimension bstack_sort_dimensions[] = { 2767 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from), 2768 DIM(SORT_DSO_TO, "dso_to", sort_dso_to), 2769 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from), 2770 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to), 2771 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict), 2772 DIM(SORT_IN_TX, "in_tx", sort_in_tx), 2773 DIM(SORT_ABORT, "abort", sort_abort), 2774 DIM(SORT_CYCLES, "cycles", sort_cycles), 2775 DIM(SORT_SRCLINE_FROM, "srcline_from", sort_srcline_from), 2776 DIM(SORT_SRCLINE_TO, "srcline_to", sort_srcline_to), 2777 DIM(SORT_SYM_IPC, "ipc_lbr", sort_sym_ipc), 2778 DIM(SORT_ADDR_FROM, "addr_from", sort_addr_from), 2779 DIM(SORT_ADDR_TO, "addr_to", sort_addr_to), 2780 DIM(SORT_CALLCHAIN_BRANCH_PREDICTED, 2781 "callchain_branch_predicted", 2782 sort_callchain_branch_predicted), 2783 DIM(SORT_CALLCHAIN_BRANCH_ABORT, 2784 "callchain_branch_abort", 2785 sort_callchain_branch_abort), 2786 DIM(SORT_CALLCHAIN_BRANCH_CYCLES, 2787 "callchain_branch_cycles", 2788 sort_callchain_branch_cycles) 2789 }; 2790 2791 #undef DIM 2792 2793 #define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) } 2794 2795 static struct sort_dimension memory_sort_dimensions[] = { 2796 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym), 2797 DIM(SORT_MEM_IADDR_SYMBOL, "symbol_iaddr", sort_mem_iaddr_sym), 2798 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso), 2799 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked), 2800 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb), 2801 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), 2802 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop), 2803 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline), 2804 DIM(SORT_MEM_PHYS_DADDR, "phys_daddr", sort_mem_phys_daddr), 2805 DIM(SORT_MEM_DATA_PAGE_SIZE, "data_page_size", sort_mem_data_page_size), 2806 DIM(SORT_MEM_BLOCKED, "blocked", sort_mem_blocked), 2807 }; 2808 2809 #undef DIM 2810 2811 struct hpp_dimension { 2812 const char *name; 2813 struct perf_hpp_fmt *fmt; 2814 int taken; 2815 int was_taken; 2816 int mem_mode; 2817 }; 2818 2819 #define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], } 2820 #define DIM_MEM(d, n) { .name = n, .fmt = &perf_hpp__format[d], .mem_mode = 1, } 2821 2822 static struct hpp_dimension hpp_sort_dimensions[] = { 2823 DIM(PERF_HPP__OVERHEAD, "overhead"), 2824 DIM(PERF_HPP__LATENCY, "latency"), 2825 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"), 2826 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"), 2827 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"), 2828 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"), 2829 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"), 2830 DIM(PERF_HPP__LATENCY_ACC, "latency_children"), 2831 DIM(PERF_HPP__SAMPLES, "sample"), 2832 DIM(PERF_HPP__PERIOD, "period"), 2833 DIM(PERF_HPP__WEIGHT1, "weight1"), 2834 DIM(PERF_HPP__WEIGHT2, "weight2"), 2835 DIM(PERF_HPP__WEIGHT3, "weight3"), 2836 /* aliases for weight_struct */ 2837 DIM(PERF_HPP__WEIGHT2, "ins_lat"), 2838 DIM(PERF_HPP__WEIGHT3, "retire_lat"), 2839 DIM(PERF_HPP__WEIGHT3, "p_stage_cyc"), 2840 /* used for output only when SORT_MODE__MEM */ 2841 DIM_MEM(PERF_HPP__MEM_STAT_OP, "op"), 2842 DIM_MEM(PERF_HPP__MEM_STAT_CACHE, "cache"), 2843 DIM_MEM(PERF_HPP__MEM_STAT_MEMORY, "memory"), 2844 DIM_MEM(PERF_HPP__MEM_STAT_SNOOP, "snoop"), 2845 DIM_MEM(PERF_HPP__MEM_STAT_DTLB, "dtlb"), 2846 }; 2847 2848 #undef DIM_MEM 2849 #undef DIM 2850 2851 struct hpp_sort_entry { 2852 struct perf_hpp_fmt hpp; 2853 struct sort_entry *se; 2854 }; 2855 2856 void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists) 2857 { 2858 struct hpp_sort_entry *hse; 2859 2860 if (!perf_hpp__is_sort_entry(fmt)) 2861 return; 2862 2863 hse = container_of(fmt, struct hpp_sort_entry, hpp); 2864 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name)); 2865 } 2866 2867 static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 2868 struct hists *hists, int line, 2869 int *span __maybe_unused) 2870 { 2871 struct hpp_sort_entry *hse; 2872 size_t len = fmt->user_len; 2873 const char *hdr = ""; 2874 2875 if (line == hists->hpp_list->nr_header_lines - 1) 2876 hdr = fmt->name; 2877 2878 hse = container_of(fmt, struct hpp_sort_entry, hpp); 2879 2880 if (!len) 2881 len = hists__col_len(hists, hse->se->se_width_idx); 2882 2883 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, hdr); 2884 } 2885 2886 static int __sort__hpp_width(struct perf_hpp_fmt *fmt, 2887 struct perf_hpp *hpp __maybe_unused, 2888 struct hists *hists) 2889 { 2890 struct hpp_sort_entry *hse; 2891 size_t len = fmt->user_len; 2892 2893 hse = container_of(fmt, struct hpp_sort_entry, hpp); 2894 2895 if (!len) 2896 len = hists__col_len(hists, hse->se->se_width_idx); 2897 2898 return len; 2899 } 2900 2901 static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 2902 struct hist_entry *he) 2903 { 2904 struct hpp_sort_entry *hse; 2905 size_t len = fmt->user_len; 2906 2907 hse = container_of(fmt, struct hpp_sort_entry, hpp); 2908 2909 if (!len) 2910 len = hists__col_len(he->hists, hse->se->se_width_idx); 2911 2912 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len); 2913 } 2914 2915 static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt, 2916 struct hist_entry *a, struct hist_entry *b) 2917 { 2918 struct hpp_sort_entry *hse; 2919 2920 hse = container_of(fmt, struct hpp_sort_entry, hpp); 2921 return hse->se->se_cmp(a, b); 2922 } 2923 2924 static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt, 2925 struct hist_entry *a, struct hist_entry *b) 2926 { 2927 struct hpp_sort_entry *hse; 2928 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *); 2929 2930 hse = container_of(fmt, struct hpp_sort_entry, hpp); 2931 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp; 2932 return collapse_fn(a, b); 2933 } 2934 2935 static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt, 2936 struct hist_entry *a, struct hist_entry *b) 2937 { 2938 struct hpp_sort_entry *hse; 2939 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *); 2940 2941 hse = container_of(fmt, struct hpp_sort_entry, hpp); 2942 sort_fn = hse->se->se_sort ?: hse->se->se_cmp; 2943 return sort_fn(a, b); 2944 } 2945 2946 bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format) 2947 { 2948 return format->header == __sort__hpp_header; 2949 } 2950 2951 #define MK_SORT_ENTRY_CHK(key) \ 2952 bool perf_hpp__is_ ## key ## _entry(struct perf_hpp_fmt *fmt) \ 2953 { \ 2954 struct hpp_sort_entry *hse; \ 2955 \ 2956 if (!perf_hpp__is_sort_entry(fmt)) \ 2957 return false; \ 2958 \ 2959 hse = container_of(fmt, struct hpp_sort_entry, hpp); \ 2960 return hse->se == &sort_ ## key ; \ 2961 } 2962 2963 #ifdef HAVE_LIBTRACEEVENT 2964 MK_SORT_ENTRY_CHK(trace) 2965 #else 2966 bool perf_hpp__is_trace_entry(struct perf_hpp_fmt *fmt __maybe_unused) 2967 { 2968 return false; 2969 } 2970 #endif 2971 MK_SORT_ENTRY_CHK(srcline) 2972 MK_SORT_ENTRY_CHK(srcfile) 2973 MK_SORT_ENTRY_CHK(thread) 2974 MK_SORT_ENTRY_CHK(comm) 2975 MK_SORT_ENTRY_CHK(dso) 2976 MK_SORT_ENTRY_CHK(sym) 2977 MK_SORT_ENTRY_CHK(parallelism) 2978 2979 2980 static bool __sort__hpp_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) 2981 { 2982 struct hpp_sort_entry *hse_a; 2983 struct hpp_sort_entry *hse_b; 2984 2985 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b)) 2986 return false; 2987 2988 hse_a = container_of(a, struct hpp_sort_entry, hpp); 2989 hse_b = container_of(b, struct hpp_sort_entry, hpp); 2990 2991 return hse_a->se == hse_b->se; 2992 } 2993 2994 static void hse_free(struct perf_hpp_fmt *fmt) 2995 { 2996 struct hpp_sort_entry *hse; 2997 2998 hse = container_of(fmt, struct hpp_sort_entry, hpp); 2999 free(hse); 3000 } 3001 3002 static void hse_init(struct perf_hpp_fmt *fmt, struct hist_entry *he) 3003 { 3004 struct hpp_sort_entry *hse; 3005 3006 if (!perf_hpp__is_sort_entry(fmt)) 3007 return; 3008 3009 hse = container_of(fmt, struct hpp_sort_entry, hpp); 3010 3011 if (hse->se->se_init) 3012 hse->se->se_init(he); 3013 } 3014 3015 static struct hpp_sort_entry * 3016 __sort_dimension__alloc_hpp(struct sort_dimension *sd, int level) 3017 { 3018 struct hpp_sort_entry *hse; 3019 3020 hse = malloc(sizeof(*hse)); 3021 if (hse == NULL) { 3022 pr_err("Memory allocation failed\n"); 3023 return NULL; 3024 } 3025 3026 hse->se = sd->entry; 3027 hse->hpp.name = sd->entry->se_header; 3028 hse->hpp.header = __sort__hpp_header; 3029 hse->hpp.width = __sort__hpp_width; 3030 hse->hpp.entry = __sort__hpp_entry; 3031 hse->hpp.color = NULL; 3032 3033 hse->hpp.cmp = __sort__hpp_cmp; 3034 hse->hpp.collapse = __sort__hpp_collapse; 3035 hse->hpp.sort = __sort__hpp_sort; 3036 hse->hpp.equal = __sort__hpp_equal; 3037 hse->hpp.free = hse_free; 3038 hse->hpp.init = hse_init; 3039 3040 INIT_LIST_HEAD(&hse->hpp.list); 3041 INIT_LIST_HEAD(&hse->hpp.sort_list); 3042 hse->hpp.elide = false; 3043 hse->hpp.len = 0; 3044 hse->hpp.user_len = 0; 3045 hse->hpp.level = level; 3046 3047 return hse; 3048 } 3049 3050 static void hpp_free(struct perf_hpp_fmt *fmt) 3051 { 3052 free(fmt); 3053 } 3054 3055 static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd, 3056 int level) 3057 { 3058 struct perf_hpp_fmt *fmt; 3059 3060 fmt = memdup(hd->fmt, sizeof(*fmt)); 3061 if (fmt) { 3062 INIT_LIST_HEAD(&fmt->list); 3063 INIT_LIST_HEAD(&fmt->sort_list); 3064 fmt->free = hpp_free; 3065 fmt->level = level; 3066 } 3067 3068 return fmt; 3069 } 3070 3071 int hist_entry__filter(struct hist_entry *he, int type, const void *arg) 3072 { 3073 struct perf_hpp_fmt *fmt; 3074 struct hpp_sort_entry *hse; 3075 int ret = -1; 3076 int r; 3077 3078 perf_hpp_list__for_each_format(he->hpp_list, fmt) { 3079 if (!perf_hpp__is_sort_entry(fmt)) 3080 continue; 3081 3082 hse = container_of(fmt, struct hpp_sort_entry, hpp); 3083 if (hse->se->se_filter == NULL) 3084 continue; 3085 3086 /* 3087 * hist entry is filtered if any of sort key in the hpp list 3088 * is applied. But it should skip non-matched filter types. 3089 */ 3090 r = hse->se->se_filter(he, type, arg); 3091 if (r >= 0) { 3092 if (ret < 0) 3093 ret = 0; 3094 ret |= r; 3095 } 3096 } 3097 3098 return ret; 3099 } 3100 3101 static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd, 3102 struct perf_hpp_list *list, 3103 int level) 3104 { 3105 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, level); 3106 3107 if (hse == NULL) 3108 return -1; 3109 3110 perf_hpp_list__register_sort_field(list, &hse->hpp); 3111 return 0; 3112 } 3113 3114 static int __sort_dimension__add_hpp_output(struct sort_dimension *sd, 3115 struct perf_hpp_list *list, 3116 int level) 3117 { 3118 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd, level); 3119 3120 if (hse == NULL) 3121 return -1; 3122 3123 perf_hpp_list__column_register(list, &hse->hpp); 3124 return 0; 3125 } 3126 3127 #ifndef HAVE_LIBTRACEEVENT 3128 bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt __maybe_unused) 3129 { 3130 return false; 3131 } 3132 bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt __maybe_unused, 3133 struct hists *hists __maybe_unused) 3134 { 3135 return false; 3136 } 3137 #else 3138 struct hpp_dynamic_entry { 3139 struct perf_hpp_fmt hpp; 3140 struct evsel *evsel; 3141 struct tep_format_field *field; 3142 unsigned dynamic_len; 3143 bool raw_trace; 3144 }; 3145 3146 static int hde_width(struct hpp_dynamic_entry *hde) 3147 { 3148 if (!hde->hpp.len) { 3149 int len = hde->dynamic_len; 3150 int namelen = strlen(hde->field->name); 3151 int fieldlen = hde->field->size; 3152 3153 if (namelen > len) 3154 len = namelen; 3155 3156 if (!(hde->field->flags & TEP_FIELD_IS_STRING)) { 3157 /* length for print hex numbers */ 3158 fieldlen = hde->field->size * 2 + 2; 3159 } 3160 if (fieldlen > len) 3161 len = fieldlen; 3162 3163 hde->hpp.len = len; 3164 } 3165 return hde->hpp.len; 3166 } 3167 3168 static void update_dynamic_len(struct hpp_dynamic_entry *hde, 3169 struct hist_entry *he) 3170 { 3171 char *str, *pos; 3172 struct tep_format_field *field = hde->field; 3173 size_t namelen; 3174 bool last = false; 3175 3176 if (hde->raw_trace) 3177 return; 3178 3179 /* parse pretty print result and update max length */ 3180 if (!he->trace_output) 3181 he->trace_output = get_trace_output(he); 3182 3183 namelen = strlen(field->name); 3184 str = he->trace_output; 3185 3186 while (str) { 3187 pos = strchr(str, ' '); 3188 if (pos == NULL) { 3189 last = true; 3190 pos = str + strlen(str); 3191 } 3192 3193 if (!strncmp(str, field->name, namelen)) { 3194 size_t len; 3195 3196 str += namelen + 1; 3197 len = pos - str; 3198 3199 if (len > hde->dynamic_len) 3200 hde->dynamic_len = len; 3201 break; 3202 } 3203 3204 if (last) 3205 str = NULL; 3206 else 3207 str = pos + 1; 3208 } 3209 } 3210 3211 static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 3212 struct hists *hists __maybe_unused, 3213 int line __maybe_unused, 3214 int *span __maybe_unused) 3215 { 3216 struct hpp_dynamic_entry *hde; 3217 size_t len = fmt->user_len; 3218 3219 hde = container_of(fmt, struct hpp_dynamic_entry, hpp); 3220 3221 if (!len) 3222 len = hde_width(hde); 3223 3224 return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name); 3225 } 3226 3227 static int __sort__hde_width(struct perf_hpp_fmt *fmt, 3228 struct perf_hpp *hpp __maybe_unused, 3229 struct hists *hists __maybe_unused) 3230 { 3231 struct hpp_dynamic_entry *hde; 3232 size_t len = fmt->user_len; 3233 3234 hde = container_of(fmt, struct hpp_dynamic_entry, hpp); 3235 3236 if (!len) 3237 len = hde_width(hde); 3238 3239 return len; 3240 } 3241 3242 bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists) 3243 { 3244 struct hpp_dynamic_entry *hde; 3245 3246 hde = container_of(fmt, struct hpp_dynamic_entry, hpp); 3247 3248 return hists_to_evsel(hists) == hde->evsel; 3249 } 3250 3251 static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 3252 struct hist_entry *he) 3253 { 3254 struct hpp_dynamic_entry *hde; 3255 size_t len = fmt->user_len; 3256 char *str, *pos; 3257 struct tep_format_field *field; 3258 size_t namelen; 3259 bool last = false; 3260 int ret; 3261 3262 hde = container_of(fmt, struct hpp_dynamic_entry, hpp); 3263 3264 if (!len) 3265 len = hde_width(hde); 3266 3267 if (hde->raw_trace) 3268 goto raw_field; 3269 3270 if (!he->trace_output) 3271 he->trace_output = get_trace_output(he); 3272 3273 field = hde->field; 3274 namelen = strlen(field->name); 3275 str = he->trace_output; 3276 3277 while (str) { 3278 pos = strchr(str, ' '); 3279 if (pos == NULL) { 3280 last = true; 3281 pos = str + strlen(str); 3282 } 3283 3284 if (!strncmp(str, field->name, namelen)) { 3285 str += namelen + 1; 3286 str = strndup(str, pos - str); 3287 3288 if (str == NULL) 3289 return scnprintf(hpp->buf, hpp->size, 3290 "%*.*s", len, len, "ERROR"); 3291 break; 3292 } 3293 3294 if (last) 3295 str = NULL; 3296 else 3297 str = pos + 1; 3298 } 3299 3300 if (str == NULL) { 3301 struct trace_seq seq; 3302 raw_field: 3303 trace_seq_init(&seq); 3304 tep_print_field(&seq, he->raw_data, hde->field); 3305 str = seq.buffer; 3306 } 3307 3308 ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str); 3309 free(str); 3310 return ret; 3311 } 3312 3313 static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt, 3314 struct hist_entry *a, struct hist_entry *b) 3315 { 3316 struct hpp_dynamic_entry *hde; 3317 struct tep_format_field *field; 3318 unsigned offset, size; 3319 3320 hde = container_of(fmt, struct hpp_dynamic_entry, hpp); 3321 3322 field = hde->field; 3323 if (field->flags & TEP_FIELD_IS_DYNAMIC) { 3324 unsigned long long dyn; 3325 3326 tep_read_number_field(field, a->raw_data, &dyn); 3327 offset = dyn & 0xffff; 3328 size = (dyn >> 16) & 0xffff; 3329 if (tep_field_is_relative(field->flags)) 3330 offset += field->offset + field->size; 3331 /* record max width for output */ 3332 if (size > hde->dynamic_len) 3333 hde->dynamic_len = size; 3334 } else { 3335 offset = field->offset; 3336 size = field->size; 3337 } 3338 3339 return memcmp(a->raw_data + offset, b->raw_data + offset, size); 3340 } 3341 3342 bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt) 3343 { 3344 return fmt->cmp == __sort__hde_cmp; 3345 } 3346 3347 static bool __sort__hde_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) 3348 { 3349 struct hpp_dynamic_entry *hde_a; 3350 struct hpp_dynamic_entry *hde_b; 3351 3352 if (!perf_hpp__is_dynamic_entry(a) || !perf_hpp__is_dynamic_entry(b)) 3353 return false; 3354 3355 hde_a = container_of(a, struct hpp_dynamic_entry, hpp); 3356 hde_b = container_of(b, struct hpp_dynamic_entry, hpp); 3357 3358 return hde_a->field == hde_b->field; 3359 } 3360 3361 static void hde_free(struct perf_hpp_fmt *fmt) 3362 { 3363 struct hpp_dynamic_entry *hde; 3364 3365 hde = container_of(fmt, struct hpp_dynamic_entry, hpp); 3366 free(hde); 3367 } 3368 3369 static void __sort__hde_init(struct perf_hpp_fmt *fmt, struct hist_entry *he) 3370 { 3371 struct hpp_dynamic_entry *hde; 3372 3373 if (!perf_hpp__is_dynamic_entry(fmt)) 3374 return; 3375 3376 hde = container_of(fmt, struct hpp_dynamic_entry, hpp); 3377 update_dynamic_len(hde, he); 3378 } 3379 3380 static struct hpp_dynamic_entry * 3381 __alloc_dynamic_entry(struct evsel *evsel, struct tep_format_field *field, 3382 int level) 3383 { 3384 struct hpp_dynamic_entry *hde; 3385 3386 hde = malloc(sizeof(*hde)); 3387 if (hde == NULL) { 3388 pr_debug("Memory allocation failed\n"); 3389 return NULL; 3390 } 3391 3392 hde->evsel = evsel; 3393 hde->field = field; 3394 hde->dynamic_len = 0; 3395 3396 hde->hpp.name = field->name; 3397 hde->hpp.header = __sort__hde_header; 3398 hde->hpp.width = __sort__hde_width; 3399 hde->hpp.entry = __sort__hde_entry; 3400 hde->hpp.color = NULL; 3401 3402 hde->hpp.init = __sort__hde_init; 3403 hde->hpp.cmp = __sort__hde_cmp; 3404 hde->hpp.collapse = __sort__hde_cmp; 3405 hde->hpp.sort = __sort__hde_cmp; 3406 hde->hpp.equal = __sort__hde_equal; 3407 hde->hpp.free = hde_free; 3408 3409 INIT_LIST_HEAD(&hde->hpp.list); 3410 INIT_LIST_HEAD(&hde->hpp.sort_list); 3411 hde->hpp.elide = false; 3412 hde->hpp.len = 0; 3413 hde->hpp.user_len = 0; 3414 hde->hpp.level = level; 3415 3416 return hde; 3417 } 3418 #endif /* HAVE_LIBTRACEEVENT */ 3419 3420 struct perf_hpp_fmt *perf_hpp_fmt__dup(struct perf_hpp_fmt *fmt) 3421 { 3422 struct perf_hpp_fmt *new_fmt = NULL; 3423 3424 if (perf_hpp__is_sort_entry(fmt)) { 3425 struct hpp_sort_entry *hse, *new_hse; 3426 3427 hse = container_of(fmt, struct hpp_sort_entry, hpp); 3428 new_hse = memdup(hse, sizeof(*hse)); 3429 if (new_hse) 3430 new_fmt = &new_hse->hpp; 3431 #ifdef HAVE_LIBTRACEEVENT 3432 } else if (perf_hpp__is_dynamic_entry(fmt)) { 3433 struct hpp_dynamic_entry *hde, *new_hde; 3434 3435 hde = container_of(fmt, struct hpp_dynamic_entry, hpp); 3436 new_hde = memdup(hde, sizeof(*hde)); 3437 if (new_hde) 3438 new_fmt = &new_hde->hpp; 3439 #endif 3440 } else { 3441 new_fmt = memdup(fmt, sizeof(*fmt)); 3442 } 3443 3444 INIT_LIST_HEAD(&new_fmt->list); 3445 INIT_LIST_HEAD(&new_fmt->sort_list); 3446 3447 return new_fmt; 3448 } 3449 3450 static int parse_field_name(char *str, char **event, char **field, char **opt) 3451 { 3452 char *event_name, *field_name, *opt_name; 3453 3454 event_name = str; 3455 field_name = strchr(str, '.'); 3456 3457 if (field_name) { 3458 *field_name++ = '\0'; 3459 } else { 3460 event_name = NULL; 3461 field_name = str; 3462 } 3463 3464 opt_name = strchr(field_name, '/'); 3465 if (opt_name) 3466 *opt_name++ = '\0'; 3467 3468 *event = event_name; 3469 *field = field_name; 3470 *opt = opt_name; 3471 3472 return 0; 3473 } 3474 3475 /* find match evsel using a given event name. The event name can be: 3476 * 1. '%' + event index (e.g. '%1' for first event) 3477 * 2. full event name (e.g. sched:sched_switch) 3478 * 3. partial event name (should not contain ':') 3479 */ 3480 static struct evsel *find_evsel(struct evlist *evlist, char *event_name) 3481 { 3482 struct evsel *evsel = NULL; 3483 struct evsel *pos; 3484 bool full_name; 3485 3486 /* case 1 */ 3487 if (event_name[0] == '%') { 3488 int nr = strtol(event_name+1, NULL, 0); 3489 3490 if (nr > evlist->core.nr_entries) 3491 return NULL; 3492 3493 evsel = evlist__first(evlist); 3494 while (--nr > 0) 3495 evsel = evsel__next(evsel); 3496 3497 return evsel; 3498 } 3499 3500 full_name = !!strchr(event_name, ':'); 3501 evlist__for_each_entry(evlist, pos) { 3502 /* case 2 */ 3503 if (full_name && evsel__name_is(pos, event_name)) 3504 return pos; 3505 /* case 3 */ 3506 if (!full_name && strstr(pos->name, event_name)) { 3507 if (evsel) { 3508 pr_debug("'%s' event is ambiguous: it can be %s or %s\n", 3509 event_name, evsel->name, pos->name); 3510 return NULL; 3511 } 3512 evsel = pos; 3513 } 3514 } 3515 3516 return evsel; 3517 } 3518 3519 #ifdef HAVE_LIBTRACEEVENT 3520 static int __dynamic_dimension__add(struct evsel *evsel, 3521 struct tep_format_field *field, 3522 bool raw_trace, int level) 3523 { 3524 struct hpp_dynamic_entry *hde; 3525 3526 hde = __alloc_dynamic_entry(evsel, field, level); 3527 if (hde == NULL) 3528 return -ENOMEM; 3529 3530 hde->raw_trace = raw_trace; 3531 3532 perf_hpp__register_sort_field(&hde->hpp); 3533 return 0; 3534 } 3535 3536 static int add_evsel_fields(struct evsel *evsel, bool raw_trace, int level) 3537 { 3538 int ret; 3539 struct tep_event *tp_format = evsel__tp_format(evsel); 3540 struct tep_format_field *field = tp_format ? tp_format->format.fields : NULL; 3541 while (field) { 3542 ret = __dynamic_dimension__add(evsel, field, raw_trace, level); 3543 if (ret < 0) 3544 return ret; 3545 3546 field = field->next; 3547 } 3548 return 0; 3549 } 3550 3551 static int add_all_dynamic_fields(struct evlist *evlist, bool raw_trace, 3552 int level) 3553 { 3554 int ret; 3555 struct evsel *evsel; 3556 3557 evlist__for_each_entry(evlist, evsel) { 3558 if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) 3559 continue; 3560 3561 ret = add_evsel_fields(evsel, raw_trace, level); 3562 if (ret < 0) 3563 return ret; 3564 } 3565 return 0; 3566 } 3567 3568 static int add_all_matching_fields(struct evlist *evlist, 3569 char *field_name, bool raw_trace, int level) 3570 { 3571 int ret = -ESRCH; 3572 struct evsel *evsel; 3573 3574 evlist__for_each_entry(evlist, evsel) { 3575 struct tep_event *tp_format; 3576 struct tep_format_field *field; 3577 3578 if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) 3579 continue; 3580 3581 tp_format = evsel__tp_format(evsel); 3582 if (tp_format == NULL) 3583 continue; 3584 3585 field = tep_find_any_field(tp_format, field_name); 3586 if (field == NULL) 3587 continue; 3588 3589 ret = __dynamic_dimension__add(evsel, field, raw_trace, level); 3590 if (ret < 0) 3591 break; 3592 } 3593 return ret; 3594 } 3595 #endif /* HAVE_LIBTRACEEVENT */ 3596 3597 static int add_dynamic_entry(struct evlist *evlist, const char *tok, 3598 int level) 3599 { 3600 char *str, *event_name, *field_name, *opt_name; 3601 struct evsel *evsel; 3602 bool raw_trace = symbol_conf.raw_trace; 3603 int ret = 0; 3604 3605 if (evlist == NULL) 3606 return -ENOENT; 3607 3608 str = strdup(tok); 3609 if (str == NULL) 3610 return -ENOMEM; 3611 3612 if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) { 3613 ret = -EINVAL; 3614 goto out; 3615 } 3616 3617 if (opt_name) { 3618 if (strcmp(opt_name, "raw")) { 3619 pr_debug("unsupported field option %s\n", opt_name); 3620 ret = -EINVAL; 3621 goto out; 3622 } 3623 raw_trace = true; 3624 } 3625 3626 #ifdef HAVE_LIBTRACEEVENT 3627 if (!strcmp(field_name, "trace_fields")) { 3628 ret = add_all_dynamic_fields(evlist, raw_trace, level); 3629 goto out; 3630 } 3631 3632 if (event_name == NULL) { 3633 ret = add_all_matching_fields(evlist, field_name, raw_trace, level); 3634 goto out; 3635 } 3636 #else 3637 evlist__for_each_entry(evlist, evsel) { 3638 if (evsel->core.attr.type == PERF_TYPE_TRACEPOINT) { 3639 pr_err("%s %s", ret ? "," : "This perf binary isn't linked with libtraceevent, can't process", evsel__name(evsel)); 3640 ret = -ENOTSUP; 3641 } 3642 } 3643 3644 if (ret) { 3645 pr_err("\n"); 3646 goto out; 3647 } 3648 #endif 3649 3650 evsel = find_evsel(evlist, event_name); 3651 if (evsel == NULL) { 3652 pr_debug("Cannot find event: %s\n", event_name); 3653 ret = -ENOENT; 3654 goto out; 3655 } 3656 3657 if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) { 3658 pr_debug("%s is not a tracepoint event\n", event_name); 3659 ret = -EINVAL; 3660 goto out; 3661 } 3662 3663 #ifdef HAVE_LIBTRACEEVENT 3664 if (!strcmp(field_name, "*")) { 3665 ret = add_evsel_fields(evsel, raw_trace, level); 3666 } else { 3667 struct tep_event *tp_format = evsel__tp_format(evsel); 3668 struct tep_format_field *field = 3669 tp_format ? tep_find_any_field(tp_format, field_name) : NULL; 3670 3671 if (field == NULL) { 3672 pr_debug("Cannot find event field for %s.%s\n", 3673 event_name, field_name); 3674 return -ENOENT; 3675 } 3676 3677 ret = __dynamic_dimension__add(evsel, field, raw_trace, level); 3678 } 3679 #else 3680 (void)level; 3681 (void)raw_trace; 3682 #endif /* HAVE_LIBTRACEEVENT */ 3683 3684 out: 3685 free(str); 3686 return ret; 3687 } 3688 3689 static int __sort_dimension__update(struct sort_dimension *sd, 3690 struct perf_hpp_list *list) 3691 { 3692 if (sd->entry == &sort_parent && parent_pattern) { 3693 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); 3694 if (ret) { 3695 char err[BUFSIZ]; 3696 3697 regerror(ret, &parent_regex, err, sizeof(err)); 3698 pr_err("Invalid regex: %s\n%s", parent_pattern, err); 3699 return -EINVAL; 3700 } 3701 list->parent = 1; 3702 } else if (sd->entry == &sort_sym) { 3703 list->sym = 1; 3704 /* 3705 * perf diff displays the performance difference amongst 3706 * two or more perf.data files. Those files could come 3707 * from different binaries. So we should not compare 3708 * their ips, but the name of symbol. 3709 */ 3710 if (sort__mode == SORT_MODE__DIFF) 3711 sd->entry->se_collapse = sort__sym_sort; 3712 3713 } else if (sd->entry == &sort_sym_offset) { 3714 list->sym = 1; 3715 } else if (sd->entry == &sort_dso) { 3716 list->dso = 1; 3717 } else if (sd->entry == &sort_socket) { 3718 list->socket = 1; 3719 } else if (sd->entry == &sort_thread) { 3720 list->thread = 1; 3721 } else if (sd->entry == &sort_comm) { 3722 list->comm = 1; 3723 } else if (sd->entry == &sort_comm_nodigit) { 3724 list->comm_nodigit = list->comm = 1; 3725 } else if (sd->entry == &sort_type_offset) { 3726 symbol_conf.annotate_data_member = true; 3727 } else if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) { 3728 list->sym = 1; 3729 } else if (sd->entry == &sort_mem_dcacheline && cacheline_size() == 0) { 3730 return -EINVAL; 3731 } else if (sd->entry == &sort_mem_daddr_sym) { 3732 list->sym = 1; 3733 } 3734 3735 if (sd->entry->se_collapse) 3736 list->need_collapse = 1; 3737 3738 return 0; 3739 } 3740 3741 static int __sort_dimension__add(struct sort_dimension *sd, 3742 struct perf_hpp_list *list, 3743 int level) 3744 { 3745 if (sd->taken) 3746 return 0; 3747 3748 if (__sort_dimension__add_hpp_sort(sd, list, level) < 0) 3749 return -1; 3750 3751 if (__sort_dimension__update(sd, list) < 0) 3752 return -1; 3753 3754 sd->taken = 1; 3755 3756 return 0; 3757 } 3758 3759 static int __hpp_dimension__add(struct hpp_dimension *hd, 3760 struct perf_hpp_list *list, 3761 int level) 3762 { 3763 struct perf_hpp_fmt *fmt; 3764 3765 if (hd->taken) 3766 return 0; 3767 3768 fmt = __hpp_dimension__alloc_hpp(hd, level); 3769 if (!fmt) 3770 return -1; 3771 3772 hd->taken = 1; 3773 hd->was_taken = 1; 3774 perf_hpp_list__register_sort_field(list, fmt); 3775 return 0; 3776 } 3777 3778 static int __sort_dimension__add_output(struct perf_hpp_list *list, 3779 struct sort_dimension *sd, 3780 int level) 3781 { 3782 if (sd->taken) 3783 return 0; 3784 3785 if (__sort_dimension__add_hpp_output(sd, list, level) < 0) 3786 return -1; 3787 3788 if (__sort_dimension__update(sd, list) < 0) 3789 return -1; 3790 3791 sd->taken = 1; 3792 return 0; 3793 } 3794 3795 static int __hpp_dimension__add_output(struct perf_hpp_list *list, 3796 struct hpp_dimension *hd, 3797 int level) 3798 { 3799 struct perf_hpp_fmt *fmt; 3800 3801 if (hd->taken) 3802 return 0; 3803 3804 fmt = __hpp_dimension__alloc_hpp(hd, level); 3805 if (!fmt) 3806 return -1; 3807 3808 hd->taken = 1; 3809 perf_hpp_list__column_register(list, fmt); 3810 return 0; 3811 } 3812 3813 int hpp_dimension__add_output(unsigned col, bool implicit) 3814 { 3815 struct hpp_dimension *hd; 3816 3817 BUG_ON(col >= PERF_HPP__MAX_INDEX); 3818 hd = &hpp_sort_dimensions[col]; 3819 if (implicit && !hd->was_taken) 3820 return 0; 3821 return __hpp_dimension__add_output(&perf_hpp_list, hd, /*level=*/0); 3822 } 3823 3824 int sort_dimension__add(struct perf_hpp_list *list, const char *tok, 3825 struct evlist *evlist, struct perf_env *env, 3826 int level) 3827 { 3828 unsigned int i, j; 3829 3830 /* 3831 * Check to see if there are any arch specific 3832 * sort dimensions not applicable for the current 3833 * architecture. If so, Skip that sort key since 3834 * we don't want to display it in the output fields. 3835 */ 3836 for (j = 0; j < ARRAY_SIZE(arch_specific_sort_keys); j++) { 3837 if (!strcmp(arch_specific_sort_keys[j], tok) && 3838 !arch_support_sort_key(tok, env)) { 3839 return 0; 3840 } 3841 } 3842 3843 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) { 3844 struct sort_dimension *sd = &common_sort_dimensions[i]; 3845 3846 if (!sd->name || strncasecmp(tok, sd->name, strlen(tok))) 3847 continue; 3848 3849 for (j = 0; j < ARRAY_SIZE(dynamic_headers); j++) { 3850 if (sd->name && !strcmp(dynamic_headers[j], sd->name)) 3851 sort_dimension_add_dynamic_header(sd, env); 3852 } 3853 3854 return __sort_dimension__add(sd, list, level); 3855 } 3856 3857 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 3858 struct sort_dimension *sd = &bstack_sort_dimensions[i]; 3859 3860 if (!sd->name || strncasecmp(tok, sd->name, strlen(tok))) 3861 continue; 3862 3863 if ((sort__mode != SORT_MODE__BRANCH) && 3864 strncasecmp(tok, "callchain_branch_predicted", 3865 strlen(tok)) && 3866 strncasecmp(tok, "callchain_branch_abort", 3867 strlen(tok)) && 3868 strncasecmp(tok, "callchain_branch_cycles", 3869 strlen(tok))) 3870 return -EINVAL; 3871 3872 __sort_dimension__add(sd, list, level); 3873 return 0; 3874 } 3875 3876 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) { 3877 struct sort_dimension *sd = &memory_sort_dimensions[i]; 3878 3879 if (!sd->name || strncasecmp(tok, sd->name, strlen(tok))) 3880 continue; 3881 3882 if (sort__mode != SORT_MODE__MEMORY) 3883 return -EINVAL; 3884 3885 __sort_dimension__add(sd, list, level); 3886 return 0; 3887 } 3888 3889 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { 3890 struct hpp_dimension *hd = &hpp_sort_dimensions[i]; 3891 3892 if (strncasecmp(tok, hd->name, strlen(tok))) 3893 continue; 3894 3895 return __hpp_dimension__add(hd, list, level); 3896 } 3897 3898 if (!add_dynamic_entry(evlist, tok, level)) 3899 return 0; 3900 3901 return -ESRCH; 3902 } 3903 3904 /* This should match with sort_dimension__add() above */ 3905 static bool is_hpp_sort_key(const char *key, struct perf_env *env) 3906 { 3907 unsigned i; 3908 3909 for (i = 0; i < ARRAY_SIZE(arch_specific_sort_keys); i++) { 3910 if (!strcmp(arch_specific_sort_keys[i], key) && 3911 !arch_support_sort_key(key, env)) { 3912 return false; 3913 } 3914 } 3915 3916 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) { 3917 struct sort_dimension *sd = &common_sort_dimensions[i]; 3918 3919 if (sd->name && !strncasecmp(key, sd->name, strlen(key))) 3920 return false; 3921 } 3922 3923 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { 3924 struct hpp_dimension *hd = &hpp_sort_dimensions[i]; 3925 3926 if (!strncasecmp(key, hd->name, strlen(key))) 3927 return true; 3928 } 3929 return false; 3930 } 3931 3932 static int setup_sort_list(struct perf_hpp_list *list, char *str, 3933 struct evlist *evlist, struct perf_env *env) 3934 { 3935 char *tmp, *tok; 3936 int ret = 0; 3937 int level = 0; 3938 int next_level = 1; 3939 int prev_level = 0; 3940 bool in_group = false; 3941 bool prev_was_hpp = false; 3942 3943 do { 3944 tok = str; 3945 tmp = strpbrk(str, "{}, "); 3946 if (tmp) { 3947 if (in_group) 3948 next_level = level; 3949 else 3950 next_level = level + 1; 3951 3952 if (*tmp == '{') 3953 in_group = true; 3954 else if (*tmp == '}') 3955 in_group = false; 3956 3957 *tmp = '\0'; 3958 str = tmp + 1; 3959 } 3960 3961 if (*tok) { 3962 if (is_hpp_sort_key(tok, env)) { 3963 /* keep output (hpp) sort keys in the same level */ 3964 if (prev_was_hpp) { 3965 bool next_same = (level == next_level); 3966 3967 level = prev_level; 3968 next_level = next_same ? level : level+1; 3969 } 3970 prev_was_hpp = true; 3971 } else { 3972 prev_was_hpp = false; 3973 } 3974 3975 ret = sort_dimension__add(list, tok, evlist, env, level); 3976 if (ret == -EINVAL) { 3977 if (!cacheline_size() && !strncasecmp(tok, "dcacheline", strlen(tok))) 3978 ui__error("The \"dcacheline\" --sort key needs to know the cacheline size and it couldn't be determined on this system"); 3979 else 3980 ui__error("Invalid --sort key: `%s'", tok); 3981 break; 3982 } else if (ret == -ESRCH) { 3983 ui__error("Unknown --sort key: `%s'", tok); 3984 break; 3985 } 3986 prev_level = level; 3987 } 3988 3989 level = next_level; 3990 } while (tmp); 3991 3992 return ret; 3993 } 3994 3995 static const char *get_default_sort_order(struct evlist *evlist) 3996 { 3997 const char *default_sort_orders[] = { 3998 default_sort_order, 3999 default_branch_sort_order, 4000 default_mem_sort_order, 4001 default_top_sort_order, 4002 default_diff_sort_order, 4003 default_tracepoint_sort_order, 4004 }; 4005 bool use_trace = true; 4006 struct evsel *evsel; 4007 4008 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders)); 4009 4010 if (evlist == NULL || evlist__empty(evlist)) 4011 goto out_no_evlist; 4012 4013 evlist__for_each_entry(evlist, evsel) { 4014 if (evsel->core.attr.type != PERF_TYPE_TRACEPOINT) { 4015 use_trace = false; 4016 break; 4017 } 4018 } 4019 4020 if (use_trace) { 4021 sort__mode = SORT_MODE__TRACEPOINT; 4022 if (symbol_conf.raw_trace) 4023 return "trace_fields"; 4024 } 4025 out_no_evlist: 4026 return default_sort_orders[sort__mode]; 4027 } 4028 4029 static int setup_sort_order(struct evlist *evlist) 4030 { 4031 char *new_sort_order; 4032 4033 /* 4034 * Append '+'-prefixed sort order to the default sort 4035 * order string. 4036 */ 4037 if (!sort_order || is_strict_order(sort_order)) 4038 return 0; 4039 4040 if (sort_order[1] == '\0') { 4041 ui__error("Invalid --sort key: `+'"); 4042 return -EINVAL; 4043 } 4044 4045 /* 4046 * We allocate new sort_order string, but we never free it, 4047 * because it's checked over the rest of the code. 4048 */ 4049 if (asprintf(&new_sort_order, "%s,%s", 4050 get_default_sort_order(evlist), sort_order + 1) < 0) { 4051 pr_err("Not enough memory to set up --sort"); 4052 return -ENOMEM; 4053 } 4054 4055 sort_order = new_sort_order; 4056 return 0; 4057 } 4058 4059 /* 4060 * Adds 'pre,' prefix into 'str' is 'pre' is 4061 * not already part of 'str'. 4062 */ 4063 static char *prefix_if_not_in(const char *pre, char *str) 4064 { 4065 char *n; 4066 4067 if (!str || strstr(str, pre)) 4068 return str; 4069 4070 if (asprintf(&n, "%s,%s", pre, str) < 0) 4071 n = NULL; 4072 4073 free(str); 4074 return n; 4075 } 4076 4077 static char *setup_overhead(char *keys) 4078 { 4079 if (sort__mode == SORT_MODE__DIFF) 4080 return keys; 4081 4082 if (symbol_conf.prefer_latency) { 4083 keys = prefix_if_not_in("overhead", keys); 4084 keys = prefix_if_not_in("latency", keys); 4085 if (symbol_conf.cumulate_callchain) { 4086 keys = prefix_if_not_in("overhead_children", keys); 4087 keys = prefix_if_not_in("latency_children", keys); 4088 } 4089 } else if (!keys || (!strstr(keys, "overhead") && 4090 !strstr(keys, "latency"))) { 4091 if (symbol_conf.enable_latency) 4092 keys = prefix_if_not_in("latency", keys); 4093 keys = prefix_if_not_in("overhead", keys); 4094 if (symbol_conf.cumulate_callchain) { 4095 if (symbol_conf.enable_latency) 4096 keys = prefix_if_not_in("latency_children", keys); 4097 keys = prefix_if_not_in("overhead_children", keys); 4098 } 4099 } 4100 4101 return keys; 4102 } 4103 4104 static int __setup_sorting(struct evlist *evlist, struct perf_env *env) 4105 { 4106 char *str; 4107 const char *sort_keys; 4108 int ret = 0; 4109 4110 ret = setup_sort_order(evlist); 4111 if (ret) 4112 return ret; 4113 4114 sort_keys = sort_order; 4115 if (sort_keys == NULL) { 4116 if (is_strict_order(field_order)) { 4117 /* 4118 * If user specified field order but no sort order, 4119 * we'll honor it and not add default sort orders. 4120 */ 4121 return 0; 4122 } 4123 4124 sort_keys = get_default_sort_order(evlist); 4125 } 4126 4127 str = strdup(sort_keys); 4128 if (str == NULL) { 4129 pr_err("Not enough memory to setup sort keys"); 4130 return -ENOMEM; 4131 } 4132 4133 /* 4134 * Prepend overhead fields for backward compatibility. 4135 */ 4136 if (!is_strict_order(field_order)) { 4137 str = setup_overhead(str); 4138 if (str == NULL) { 4139 pr_err("Not enough memory to setup overhead keys"); 4140 return -ENOMEM; 4141 } 4142 } 4143 4144 ret = setup_sort_list(&perf_hpp_list, str, evlist, env); 4145 4146 free(str); 4147 return ret; 4148 } 4149 4150 void perf_hpp__set_elide(int idx, bool elide) 4151 { 4152 struct perf_hpp_fmt *fmt; 4153 struct hpp_sort_entry *hse; 4154 4155 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) { 4156 if (!perf_hpp__is_sort_entry(fmt)) 4157 continue; 4158 4159 hse = container_of(fmt, struct hpp_sort_entry, hpp); 4160 if (hse->se->se_width_idx == idx) { 4161 fmt->elide = elide; 4162 break; 4163 } 4164 } 4165 } 4166 4167 static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp) 4168 { 4169 if (list && strlist__nr_entries(list) == 1) { 4170 if (fp != NULL) 4171 fprintf(fp, "# %s: %s\n", list_name, 4172 strlist__entry(list, 0)->s); 4173 return true; 4174 } 4175 return false; 4176 } 4177 4178 static bool get_elide(int idx, FILE *output) 4179 { 4180 switch (idx) { 4181 case HISTC_SYMBOL: 4182 return __get_elide(symbol_conf.sym_list, "symbol", output); 4183 case HISTC_DSO: 4184 return __get_elide(symbol_conf.dso_list, "dso", output); 4185 case HISTC_COMM: 4186 case HISTC_COMM_NODIGIT: 4187 return __get_elide(symbol_conf.comm_list, "comm", output); 4188 default: 4189 break; 4190 } 4191 4192 if (sort__mode != SORT_MODE__BRANCH) 4193 return false; 4194 4195 switch (idx) { 4196 case HISTC_SYMBOL_FROM: 4197 return __get_elide(symbol_conf.sym_from_list, "sym_from", output); 4198 case HISTC_SYMBOL_TO: 4199 return __get_elide(symbol_conf.sym_to_list, "sym_to", output); 4200 case HISTC_DSO_FROM: 4201 return __get_elide(symbol_conf.dso_from_list, "dso_from", output); 4202 case HISTC_DSO_TO: 4203 return __get_elide(symbol_conf.dso_to_list, "dso_to", output); 4204 case HISTC_ADDR_FROM: 4205 return __get_elide(symbol_conf.sym_from_list, "addr_from", output); 4206 case HISTC_ADDR_TO: 4207 return __get_elide(symbol_conf.sym_to_list, "addr_to", output); 4208 default: 4209 break; 4210 } 4211 4212 return false; 4213 } 4214 4215 void sort__setup_elide(FILE *output) 4216 { 4217 struct perf_hpp_fmt *fmt; 4218 struct hpp_sort_entry *hse; 4219 4220 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) { 4221 if (!perf_hpp__is_sort_entry(fmt)) 4222 continue; 4223 4224 hse = container_of(fmt, struct hpp_sort_entry, hpp); 4225 fmt->elide = get_elide(hse->se->se_width_idx, output); 4226 } 4227 4228 /* 4229 * It makes no sense to elide all of sort entries. 4230 * Just revert them to show up again. 4231 */ 4232 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) { 4233 if (!perf_hpp__is_sort_entry(fmt)) 4234 continue; 4235 4236 if (!fmt->elide) 4237 return; 4238 } 4239 4240 perf_hpp_list__for_each_format(&perf_hpp_list, fmt) { 4241 if (!perf_hpp__is_sort_entry(fmt)) 4242 continue; 4243 4244 fmt->elide = false; 4245 } 4246 } 4247 4248 int output_field_add(struct perf_hpp_list *list, const char *tok, int *level) 4249 { 4250 unsigned int i; 4251 4252 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { 4253 struct hpp_dimension *hd = &hpp_sort_dimensions[i]; 4254 4255 if (strncasecmp(tok, hd->name, strlen(tok))) 4256 continue; 4257 4258 if (!strcasecmp(tok, "weight")) 4259 ui__warning("--fields weight shows the average value unlike in the --sort key.\n"); 4260 4261 if (hd->mem_mode && sort__mode != SORT_MODE__MEMORY) 4262 continue; 4263 4264 return __hpp_dimension__add_output(list, hd, *level); 4265 } 4266 4267 /* 4268 * A non-output field will increase level so that it can be in a 4269 * different hierarchy. 4270 */ 4271 (*level)++; 4272 4273 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) { 4274 struct sort_dimension *sd = &common_sort_dimensions[i]; 4275 4276 if (!sd->name || strncasecmp(tok, sd->name, strlen(tok))) 4277 continue; 4278 4279 return __sort_dimension__add_output(list, sd, *level); 4280 } 4281 4282 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 4283 struct sort_dimension *sd = &bstack_sort_dimensions[i]; 4284 4285 if (!sd->name || strncasecmp(tok, sd->name, strlen(tok))) 4286 continue; 4287 4288 if (sort__mode != SORT_MODE__BRANCH) 4289 return -EINVAL; 4290 4291 return __sort_dimension__add_output(list, sd, *level); 4292 } 4293 4294 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) { 4295 struct sort_dimension *sd = &memory_sort_dimensions[i]; 4296 4297 if (!sd->name || strncasecmp(tok, sd->name, strlen(tok))) 4298 continue; 4299 4300 if (sort__mode != SORT_MODE__MEMORY) 4301 return -EINVAL; 4302 4303 return __sort_dimension__add_output(list, sd, *level); 4304 } 4305 4306 return -ESRCH; 4307 } 4308 4309 static int setup_output_list(struct perf_hpp_list *list, char *str) 4310 { 4311 char *tmp, *tok; 4312 int ret = 0; 4313 int level = 0; 4314 4315 for (tok = strtok_r(str, ", ", &tmp); 4316 tok; tok = strtok_r(NULL, ", ", &tmp)) { 4317 ret = output_field_add(list, tok, &level); 4318 if (ret == -EINVAL) { 4319 ui__error("Invalid --fields key: `%s'", tok); 4320 break; 4321 } else if (ret == -ESRCH) { 4322 ui__error("Unknown --fields key: `%s'", tok); 4323 break; 4324 } 4325 } 4326 4327 return ret; 4328 } 4329 4330 void reset_dimensions(void) 4331 { 4332 unsigned int i; 4333 4334 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) 4335 common_sort_dimensions[i].taken = 0; 4336 4337 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) 4338 hpp_sort_dimensions[i].taken = 0; 4339 4340 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) 4341 bstack_sort_dimensions[i].taken = 0; 4342 4343 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) 4344 memory_sort_dimensions[i].taken = 0; 4345 } 4346 4347 bool is_strict_order(const char *order) 4348 { 4349 return order && (*order != '+'); 4350 } 4351 4352 static int __setup_output_field(void) 4353 { 4354 char *str, *strp; 4355 int ret = -EINVAL; 4356 4357 if (field_order == NULL) 4358 return 0; 4359 4360 strp = str = strdup(field_order); 4361 if (str == NULL) { 4362 pr_err("Not enough memory to setup output fields"); 4363 return -ENOMEM; 4364 } 4365 4366 if (!is_strict_order(field_order)) 4367 strp++; 4368 4369 if (!strlen(strp)) { 4370 ui__error("Invalid --fields key: `+'"); 4371 goto out; 4372 } 4373 4374 ret = setup_output_list(&perf_hpp_list, strp); 4375 4376 out: 4377 free(str); 4378 return ret; 4379 } 4380 4381 int setup_sorting(struct evlist *evlist, struct perf_env *env) 4382 { 4383 int err; 4384 4385 err = __setup_sorting(evlist, env); 4386 if (err < 0) 4387 return err; 4388 4389 if (parent_pattern != default_parent_pattern) { 4390 err = sort_dimension__add(&perf_hpp_list, "parent", evlist, env, -1); 4391 if (err < 0) 4392 return err; 4393 } 4394 4395 reset_dimensions(); 4396 4397 /* 4398 * perf diff doesn't use default hpp output fields. 4399 */ 4400 if (sort__mode != SORT_MODE__DIFF) 4401 perf_hpp__init(); 4402 4403 err = __setup_output_field(); 4404 if (err < 0) 4405 return err; 4406 4407 err = perf_hpp__alloc_mem_stats(&perf_hpp_list, evlist); 4408 if (err < 0) 4409 return err; 4410 4411 /* copy sort keys to output fields */ 4412 perf_hpp__setup_output_field(&perf_hpp_list); 4413 /* and then copy output fields to sort keys */ 4414 perf_hpp__append_sort_keys(&perf_hpp_list); 4415 4416 /* setup hists-specific output fields */ 4417 if (perf_hpp__setup_hists_formats(&perf_hpp_list, evlist) < 0) 4418 return -1; 4419 4420 return 0; 4421 } 4422 4423 void reset_output_field(void) 4424 { 4425 perf_hpp_list.need_collapse = 0; 4426 perf_hpp_list.parent = 0; 4427 perf_hpp_list.sym = 0; 4428 perf_hpp_list.dso = 0; 4429 4430 field_order = NULL; 4431 sort_order = NULL; 4432 4433 reset_dimensions(); 4434 perf_hpp__reset_output_field(&perf_hpp_list); 4435 } 4436 4437 #define INDENT (3*8 + 1) 4438 4439 static void add_key(struct strbuf *sb, const char *str, int *llen) 4440 { 4441 if (!str) 4442 return; 4443 4444 if (*llen >= 75) { 4445 strbuf_addstr(sb, "\n\t\t\t "); 4446 *llen = INDENT; 4447 } 4448 strbuf_addf(sb, " %s", str); 4449 *llen += strlen(str) + 1; 4450 } 4451 4452 static void add_sort_string(struct strbuf *sb, struct sort_dimension *s, int n, 4453 int *llen) 4454 { 4455 int i; 4456 4457 for (i = 0; i < n; i++) 4458 add_key(sb, s[i].name, llen); 4459 } 4460 4461 static void add_hpp_sort_string(struct strbuf *sb, struct hpp_dimension *s, int n, 4462 int *llen) 4463 { 4464 int i; 4465 4466 for (i = 0; i < n; i++) 4467 add_key(sb, s[i].name, llen); 4468 } 4469 4470 char *sort_help(const char *prefix, enum sort_mode mode) 4471 { 4472 struct strbuf sb; 4473 char *s; 4474 int len = strlen(prefix) + INDENT; 4475 4476 strbuf_init(&sb, 300); 4477 strbuf_addstr(&sb, prefix); 4478 add_hpp_sort_string(&sb, hpp_sort_dimensions, 4479 ARRAY_SIZE(hpp_sort_dimensions), &len); 4480 add_sort_string(&sb, common_sort_dimensions, 4481 ARRAY_SIZE(common_sort_dimensions), &len); 4482 if (mode == SORT_MODE__NORMAL || mode == SORT_MODE__BRANCH) 4483 add_sort_string(&sb, bstack_sort_dimensions, 4484 ARRAY_SIZE(bstack_sort_dimensions), &len); 4485 if (mode == SORT_MODE__NORMAL || mode == SORT_MODE__MEMORY) 4486 add_sort_string(&sb, memory_sort_dimensions, 4487 ARRAY_SIZE(memory_sort_dimensions), &len); 4488 s = strbuf_detach(&sb, NULL); 4489 strbuf_release(&sb); 4490 return s; 4491 } 4492