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