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