1 #include <sys/mman.h> 2 #include "sort.h" 3 #include "hist.h" 4 #include "comm.h" 5 #include "symbol.h" 6 #include "evsel.h" 7 8 regex_t parent_regex; 9 const char default_parent_pattern[] = "^sys_|^do_page_fault"; 10 const char *parent_pattern = default_parent_pattern; 11 const char default_sort_order[] = "comm,dso,symbol"; 12 const char default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cycles"; 13 const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked"; 14 const char default_top_sort_order[] = "dso,symbol"; 15 const char default_diff_sort_order[] = "dso,symbol"; 16 const char *sort_order; 17 const char *field_order; 18 regex_t ignore_callees_regex; 19 int have_ignore_callees = 0; 20 int sort__need_collapse = 0; 21 int sort__has_parent = 0; 22 int sort__has_sym = 0; 23 int sort__has_dso = 0; 24 int sort__has_socket = 0; 25 enum sort_mode sort__mode = SORT_MODE__NORMAL; 26 27 28 static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) 29 { 30 int n; 31 va_list ap; 32 33 va_start(ap, fmt); 34 n = vsnprintf(bf, size, fmt, ap); 35 if (symbol_conf.field_sep && n > 0) { 36 char *sep = bf; 37 38 while (1) { 39 sep = strchr(sep, *symbol_conf.field_sep); 40 if (sep == NULL) 41 break; 42 *sep = '.'; 43 } 44 } 45 va_end(ap); 46 47 if (n >= (int)size) 48 return size - 1; 49 return n; 50 } 51 52 static int64_t cmp_null(const void *l, const void *r) 53 { 54 if (!l && !r) 55 return 0; 56 else if (!l) 57 return -1; 58 else 59 return 1; 60 } 61 62 /* --sort pid */ 63 64 static int64_t 65 sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) 66 { 67 return right->thread->tid - left->thread->tid; 68 } 69 70 static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf, 71 size_t size, unsigned int width) 72 { 73 const char *comm = thread__comm_str(he->thread); 74 75 width = max(7U, width) - 6; 76 return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid, 77 width, width, comm ?: ""); 78 } 79 80 struct sort_entry sort_thread = { 81 .se_header = " Pid:Command", 82 .se_cmp = sort__thread_cmp, 83 .se_snprintf = hist_entry__thread_snprintf, 84 .se_width_idx = HISTC_THREAD, 85 }; 86 87 /* --sort comm */ 88 89 static int64_t 90 sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) 91 { 92 /* Compare the addr that should be unique among comm */ 93 return strcmp(comm__str(right->comm), comm__str(left->comm)); 94 } 95 96 static int64_t 97 sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) 98 { 99 /* Compare the addr that should be unique among comm */ 100 return strcmp(comm__str(right->comm), comm__str(left->comm)); 101 } 102 103 static int64_t 104 sort__comm_sort(struct hist_entry *left, struct hist_entry *right) 105 { 106 return strcmp(comm__str(right->comm), comm__str(left->comm)); 107 } 108 109 static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, 110 size_t size, unsigned int width) 111 { 112 return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm)); 113 } 114 115 struct sort_entry sort_comm = { 116 .se_header = "Command", 117 .se_cmp = sort__comm_cmp, 118 .se_collapse = sort__comm_collapse, 119 .se_sort = sort__comm_sort, 120 .se_snprintf = hist_entry__comm_snprintf, 121 .se_width_idx = HISTC_COMM, 122 }; 123 124 /* --sort dso */ 125 126 static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) 127 { 128 struct dso *dso_l = map_l ? map_l->dso : NULL; 129 struct dso *dso_r = map_r ? map_r->dso : NULL; 130 const char *dso_name_l, *dso_name_r; 131 132 if (!dso_l || !dso_r) 133 return cmp_null(dso_r, dso_l); 134 135 if (verbose) { 136 dso_name_l = dso_l->long_name; 137 dso_name_r = dso_r->long_name; 138 } else { 139 dso_name_l = dso_l->short_name; 140 dso_name_r = dso_r->short_name; 141 } 142 143 return strcmp(dso_name_l, dso_name_r); 144 } 145 146 static int64_t 147 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 148 { 149 return _sort__dso_cmp(right->ms.map, left->ms.map); 150 } 151 152 static int _hist_entry__dso_snprintf(struct map *map, char *bf, 153 size_t size, unsigned int width) 154 { 155 if (map && map->dso) { 156 const char *dso_name = !verbose ? map->dso->short_name : 157 map->dso->long_name; 158 return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name); 159 } 160 161 return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]"); 162 } 163 164 static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf, 165 size_t size, unsigned int width) 166 { 167 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width); 168 } 169 170 struct sort_entry sort_dso = { 171 .se_header = "Shared Object", 172 .se_cmp = sort__dso_cmp, 173 .se_snprintf = hist_entry__dso_snprintf, 174 .se_width_idx = HISTC_DSO, 175 }; 176 177 /* --sort symbol */ 178 179 static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip) 180 { 181 return (int64_t)(right_ip - left_ip); 182 } 183 184 static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r) 185 { 186 if (!sym_l || !sym_r) 187 return cmp_null(sym_l, sym_r); 188 189 if (sym_l == sym_r) 190 return 0; 191 192 if (sym_l->start != sym_r->start) 193 return (int64_t)(sym_r->start - sym_l->start); 194 195 return (int64_t)(sym_r->end - sym_l->end); 196 } 197 198 static int64_t 199 sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 200 { 201 int64_t ret; 202 203 if (!left->ms.sym && !right->ms.sym) 204 return _sort__addr_cmp(left->ip, right->ip); 205 206 /* 207 * comparing symbol address alone is not enough since it's a 208 * relative address within a dso. 209 */ 210 if (!sort__has_dso) { 211 ret = sort__dso_cmp(left, right); 212 if (ret != 0) 213 return ret; 214 } 215 216 return _sort__sym_cmp(left->ms.sym, right->ms.sym); 217 } 218 219 static int64_t 220 sort__sym_sort(struct hist_entry *left, struct hist_entry *right) 221 { 222 if (!left->ms.sym || !right->ms.sym) 223 return cmp_null(left->ms.sym, right->ms.sym); 224 225 return strcmp(right->ms.sym->name, left->ms.sym->name); 226 } 227 228 static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, 229 u64 ip, char level, char *bf, size_t size, 230 unsigned int width) 231 { 232 size_t ret = 0; 233 234 if (verbose) { 235 char o = map ? dso__symtab_origin(map->dso) : '!'; 236 ret += repsep_snprintf(bf, size, "%-#*llx %c ", 237 BITS_PER_LONG / 4 + 2, ip, o); 238 } 239 240 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level); 241 if (sym && map) { 242 if (map->type == MAP__VARIABLE) { 243 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name); 244 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx", 245 ip - map->unmap_ip(map, sym->start)); 246 ret += repsep_snprintf(bf + ret, size - ret, "%-*s", 247 width - ret, ""); 248 } else { 249 ret += repsep_snprintf(bf + ret, size - ret, "%-*s", 250 width - ret, 251 sym->name); 252 } 253 } else { 254 size_t len = BITS_PER_LONG / 4; 255 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", 256 len, ip); 257 ret += repsep_snprintf(bf + ret, size - ret, "%-*s", 258 width - ret, ""); 259 } 260 261 if (ret > width) 262 bf[width] = '\0'; 263 264 return width; 265 } 266 267 static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, 268 size_t size, unsigned int width) 269 { 270 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip, 271 he->level, bf, size, width); 272 } 273 274 struct sort_entry sort_sym = { 275 .se_header = "Symbol", 276 .se_cmp = sort__sym_cmp, 277 .se_sort = sort__sym_sort, 278 .se_snprintf = hist_entry__sym_snprintf, 279 .se_width_idx = HISTC_SYMBOL, 280 }; 281 282 /* --sort srcline */ 283 284 static int64_t 285 sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) 286 { 287 if (!left->srcline) { 288 if (!left->ms.map) 289 left->srcline = SRCLINE_UNKNOWN; 290 else { 291 struct map *map = left->ms.map; 292 left->srcline = get_srcline(map->dso, 293 map__rip_2objdump(map, left->ip), 294 left->ms.sym, true); 295 } 296 } 297 if (!right->srcline) { 298 if (!right->ms.map) 299 right->srcline = SRCLINE_UNKNOWN; 300 else { 301 struct map *map = right->ms.map; 302 right->srcline = get_srcline(map->dso, 303 map__rip_2objdump(map, right->ip), 304 right->ms.sym, true); 305 } 306 } 307 return strcmp(right->srcline, left->srcline); 308 } 309 310 static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, 311 size_t size, unsigned int width) 312 { 313 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcline); 314 } 315 316 struct sort_entry sort_srcline = { 317 .se_header = "Source:Line", 318 .se_cmp = sort__srcline_cmp, 319 .se_snprintf = hist_entry__srcline_snprintf, 320 .se_width_idx = HISTC_SRCLINE, 321 }; 322 323 /* --sort srcfile */ 324 325 static char no_srcfile[1]; 326 327 static char *get_srcfile(struct hist_entry *e) 328 { 329 char *sf, *p; 330 struct map *map = e->ms.map; 331 332 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip), 333 e->ms.sym, false, true); 334 if (!strcmp(sf, SRCLINE_UNKNOWN)) 335 return no_srcfile; 336 p = strchr(sf, ':'); 337 if (p && *sf) { 338 *p = 0; 339 return sf; 340 } 341 free(sf); 342 return no_srcfile; 343 } 344 345 static int64_t 346 sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right) 347 { 348 if (!left->srcfile) { 349 if (!left->ms.map) 350 left->srcfile = no_srcfile; 351 else 352 left->srcfile = get_srcfile(left); 353 } 354 if (!right->srcfile) { 355 if (!right->ms.map) 356 right->srcfile = no_srcfile; 357 else 358 right->srcfile = get_srcfile(right); 359 } 360 return strcmp(right->srcfile, left->srcfile); 361 } 362 363 static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf, 364 size_t size, unsigned int width) 365 { 366 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcfile); 367 } 368 369 struct sort_entry sort_srcfile = { 370 .se_header = "Source File", 371 .se_cmp = sort__srcfile_cmp, 372 .se_snprintf = hist_entry__srcfile_snprintf, 373 .se_width_idx = HISTC_SRCFILE, 374 }; 375 376 /* --sort parent */ 377 378 static int64_t 379 sort__parent_cmp(struct hist_entry *left, struct hist_entry *right) 380 { 381 struct symbol *sym_l = left->parent; 382 struct symbol *sym_r = right->parent; 383 384 if (!sym_l || !sym_r) 385 return cmp_null(sym_l, sym_r); 386 387 return strcmp(sym_r->name, sym_l->name); 388 } 389 390 static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf, 391 size_t size, unsigned int width) 392 { 393 return repsep_snprintf(bf, size, "%-*.*s", width, width, 394 he->parent ? he->parent->name : "[other]"); 395 } 396 397 struct sort_entry sort_parent = { 398 .se_header = "Parent symbol", 399 .se_cmp = sort__parent_cmp, 400 .se_snprintf = hist_entry__parent_snprintf, 401 .se_width_idx = HISTC_PARENT, 402 }; 403 404 /* --sort cpu */ 405 406 static int64_t 407 sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right) 408 { 409 return right->cpu - left->cpu; 410 } 411 412 static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf, 413 size_t size, unsigned int width) 414 { 415 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu); 416 } 417 418 struct sort_entry sort_cpu = { 419 .se_header = "CPU", 420 .se_cmp = sort__cpu_cmp, 421 .se_snprintf = hist_entry__cpu_snprintf, 422 .se_width_idx = HISTC_CPU, 423 }; 424 425 /* --sort socket */ 426 427 static int64_t 428 sort__socket_cmp(struct hist_entry *left, struct hist_entry *right) 429 { 430 return right->socket - left->socket; 431 } 432 433 static int hist_entry__socket_snprintf(struct hist_entry *he, char *bf, 434 size_t size, unsigned int width) 435 { 436 return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket); 437 } 438 439 struct sort_entry sort_socket = { 440 .se_header = "Socket", 441 .se_cmp = sort__socket_cmp, 442 .se_snprintf = hist_entry__socket_snprintf, 443 .se_width_idx = HISTC_SOCKET, 444 }; 445 446 /* sort keys for branch stacks */ 447 448 static int64_t 449 sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right) 450 { 451 if (!left->branch_info || !right->branch_info) 452 return cmp_null(left->branch_info, right->branch_info); 453 454 return _sort__dso_cmp(left->branch_info->from.map, 455 right->branch_info->from.map); 456 } 457 458 static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf, 459 size_t size, unsigned int width) 460 { 461 if (he->branch_info) 462 return _hist_entry__dso_snprintf(he->branch_info->from.map, 463 bf, size, width); 464 else 465 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 466 } 467 468 static int64_t 469 sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) 470 { 471 if (!left->branch_info || !right->branch_info) 472 return cmp_null(left->branch_info, right->branch_info); 473 474 return _sort__dso_cmp(left->branch_info->to.map, 475 right->branch_info->to.map); 476 } 477 478 static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf, 479 size_t size, unsigned int width) 480 { 481 if (he->branch_info) 482 return _hist_entry__dso_snprintf(he->branch_info->to.map, 483 bf, size, width); 484 else 485 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 486 } 487 488 static int64_t 489 sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right) 490 { 491 struct addr_map_symbol *from_l = &left->branch_info->from; 492 struct addr_map_symbol *from_r = &right->branch_info->from; 493 494 if (!left->branch_info || !right->branch_info) 495 return cmp_null(left->branch_info, right->branch_info); 496 497 from_l = &left->branch_info->from; 498 from_r = &right->branch_info->from; 499 500 if (!from_l->sym && !from_r->sym) 501 return _sort__addr_cmp(from_l->addr, from_r->addr); 502 503 return _sort__sym_cmp(from_l->sym, from_r->sym); 504 } 505 506 static int64_t 507 sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right) 508 { 509 struct addr_map_symbol *to_l, *to_r; 510 511 if (!left->branch_info || !right->branch_info) 512 return cmp_null(left->branch_info, right->branch_info); 513 514 to_l = &left->branch_info->to; 515 to_r = &right->branch_info->to; 516 517 if (!to_l->sym && !to_r->sym) 518 return _sort__addr_cmp(to_l->addr, to_r->addr); 519 520 return _sort__sym_cmp(to_l->sym, to_r->sym); 521 } 522 523 static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf, 524 size_t size, unsigned int width) 525 { 526 if (he->branch_info) { 527 struct addr_map_symbol *from = &he->branch_info->from; 528 529 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr, 530 he->level, bf, size, width); 531 } 532 533 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 534 } 535 536 static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf, 537 size_t size, unsigned int width) 538 { 539 if (he->branch_info) { 540 struct addr_map_symbol *to = &he->branch_info->to; 541 542 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr, 543 he->level, bf, size, width); 544 } 545 546 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 547 } 548 549 struct sort_entry sort_dso_from = { 550 .se_header = "Source Shared Object", 551 .se_cmp = sort__dso_from_cmp, 552 .se_snprintf = hist_entry__dso_from_snprintf, 553 .se_width_idx = HISTC_DSO_FROM, 554 }; 555 556 struct sort_entry sort_dso_to = { 557 .se_header = "Target Shared Object", 558 .se_cmp = sort__dso_to_cmp, 559 .se_snprintf = hist_entry__dso_to_snprintf, 560 .se_width_idx = HISTC_DSO_TO, 561 }; 562 563 struct sort_entry sort_sym_from = { 564 .se_header = "Source Symbol", 565 .se_cmp = sort__sym_from_cmp, 566 .se_snprintf = hist_entry__sym_from_snprintf, 567 .se_width_idx = HISTC_SYMBOL_FROM, 568 }; 569 570 struct sort_entry sort_sym_to = { 571 .se_header = "Target Symbol", 572 .se_cmp = sort__sym_to_cmp, 573 .se_snprintf = hist_entry__sym_to_snprintf, 574 .se_width_idx = HISTC_SYMBOL_TO, 575 }; 576 577 static int64_t 578 sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right) 579 { 580 unsigned char mp, p; 581 582 if (!left->branch_info || !right->branch_info) 583 return cmp_null(left->branch_info, right->branch_info); 584 585 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred; 586 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted; 587 return mp || p; 588 } 589 590 static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf, 591 size_t size, unsigned int width){ 592 static const char *out = "N/A"; 593 594 if (he->branch_info) { 595 if (he->branch_info->flags.predicted) 596 out = "N"; 597 else if (he->branch_info->flags.mispred) 598 out = "Y"; 599 } 600 601 return repsep_snprintf(bf, size, "%-*.*s", width, width, out); 602 } 603 604 static int64_t 605 sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right) 606 { 607 return left->branch_info->flags.cycles - 608 right->branch_info->flags.cycles; 609 } 610 611 static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf, 612 size_t size, unsigned int width) 613 { 614 if (he->branch_info->flags.cycles == 0) 615 return repsep_snprintf(bf, size, "%-*s", width, "-"); 616 return repsep_snprintf(bf, size, "%-*hd", width, 617 he->branch_info->flags.cycles); 618 } 619 620 struct sort_entry sort_cycles = { 621 .se_header = "Basic Block Cycles", 622 .se_cmp = sort__cycles_cmp, 623 .se_snprintf = hist_entry__cycles_snprintf, 624 .se_width_idx = HISTC_CYCLES, 625 }; 626 627 /* --sort daddr_sym */ 628 static int64_t 629 sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right) 630 { 631 uint64_t l = 0, r = 0; 632 633 if (left->mem_info) 634 l = left->mem_info->daddr.addr; 635 if (right->mem_info) 636 r = right->mem_info->daddr.addr; 637 638 return (int64_t)(r - l); 639 } 640 641 static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf, 642 size_t size, unsigned int width) 643 { 644 uint64_t addr = 0; 645 struct map *map = NULL; 646 struct symbol *sym = NULL; 647 648 if (he->mem_info) { 649 addr = he->mem_info->daddr.addr; 650 map = he->mem_info->daddr.map; 651 sym = he->mem_info->daddr.sym; 652 } 653 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size, 654 width); 655 } 656 657 static int64_t 658 sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right) 659 { 660 struct map *map_l = NULL; 661 struct map *map_r = NULL; 662 663 if (left->mem_info) 664 map_l = left->mem_info->daddr.map; 665 if (right->mem_info) 666 map_r = right->mem_info->daddr.map; 667 668 return _sort__dso_cmp(map_l, map_r); 669 } 670 671 static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf, 672 size_t size, unsigned int width) 673 { 674 struct map *map = NULL; 675 676 if (he->mem_info) 677 map = he->mem_info->daddr.map; 678 679 return _hist_entry__dso_snprintf(map, bf, size, width); 680 } 681 682 static int64_t 683 sort__locked_cmp(struct hist_entry *left, struct hist_entry *right) 684 { 685 union perf_mem_data_src data_src_l; 686 union perf_mem_data_src data_src_r; 687 688 if (left->mem_info) 689 data_src_l = left->mem_info->data_src; 690 else 691 data_src_l.mem_lock = PERF_MEM_LOCK_NA; 692 693 if (right->mem_info) 694 data_src_r = right->mem_info->data_src; 695 else 696 data_src_r.mem_lock = PERF_MEM_LOCK_NA; 697 698 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock); 699 } 700 701 static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf, 702 size_t size, unsigned int width) 703 { 704 const char *out; 705 u64 mask = PERF_MEM_LOCK_NA; 706 707 if (he->mem_info) 708 mask = he->mem_info->data_src.mem_lock; 709 710 if (mask & PERF_MEM_LOCK_NA) 711 out = "N/A"; 712 else if (mask & PERF_MEM_LOCK_LOCKED) 713 out = "Yes"; 714 else 715 out = "No"; 716 717 return repsep_snprintf(bf, size, "%-*s", width, out); 718 } 719 720 static int64_t 721 sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right) 722 { 723 union perf_mem_data_src data_src_l; 724 union perf_mem_data_src data_src_r; 725 726 if (left->mem_info) 727 data_src_l = left->mem_info->data_src; 728 else 729 data_src_l.mem_dtlb = PERF_MEM_TLB_NA; 730 731 if (right->mem_info) 732 data_src_r = right->mem_info->data_src; 733 else 734 data_src_r.mem_dtlb = PERF_MEM_TLB_NA; 735 736 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb); 737 } 738 739 static const char * const tlb_access[] = { 740 "N/A", 741 "HIT", 742 "MISS", 743 "L1", 744 "L2", 745 "Walker", 746 "Fault", 747 }; 748 #define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *)) 749 750 static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf, 751 size_t size, unsigned int width) 752 { 753 char out[64]; 754 size_t sz = sizeof(out) - 1; /* -1 for null termination */ 755 size_t l = 0, i; 756 u64 m = PERF_MEM_TLB_NA; 757 u64 hit, miss; 758 759 out[0] = '\0'; 760 761 if (he->mem_info) 762 m = he->mem_info->data_src.mem_dtlb; 763 764 hit = m & PERF_MEM_TLB_HIT; 765 miss = m & PERF_MEM_TLB_MISS; 766 767 /* already taken care of */ 768 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS); 769 770 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) { 771 if (!(m & 0x1)) 772 continue; 773 if (l) { 774 strcat(out, " or "); 775 l += 4; 776 } 777 strncat(out, tlb_access[i], sz - l); 778 l += strlen(tlb_access[i]); 779 } 780 if (*out == '\0') 781 strcpy(out, "N/A"); 782 if (hit) 783 strncat(out, " hit", sz - l); 784 if (miss) 785 strncat(out, " miss", sz - l); 786 787 return repsep_snprintf(bf, size, "%-*s", width, out); 788 } 789 790 static int64_t 791 sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right) 792 { 793 union perf_mem_data_src data_src_l; 794 union perf_mem_data_src data_src_r; 795 796 if (left->mem_info) 797 data_src_l = left->mem_info->data_src; 798 else 799 data_src_l.mem_lvl = PERF_MEM_LVL_NA; 800 801 if (right->mem_info) 802 data_src_r = right->mem_info->data_src; 803 else 804 data_src_r.mem_lvl = PERF_MEM_LVL_NA; 805 806 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl); 807 } 808 809 static const char * const mem_lvl[] = { 810 "N/A", 811 "HIT", 812 "MISS", 813 "L1", 814 "LFB", 815 "L2", 816 "L3", 817 "Local RAM", 818 "Remote RAM (1 hop)", 819 "Remote RAM (2 hops)", 820 "Remote Cache (1 hop)", 821 "Remote Cache (2 hops)", 822 "I/O", 823 "Uncached", 824 }; 825 #define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *)) 826 827 static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf, 828 size_t size, unsigned int width) 829 { 830 char out[64]; 831 size_t sz = sizeof(out) - 1; /* -1 for null termination */ 832 size_t i, l = 0; 833 u64 m = PERF_MEM_LVL_NA; 834 u64 hit, miss; 835 836 if (he->mem_info) 837 m = he->mem_info->data_src.mem_lvl; 838 839 out[0] = '\0'; 840 841 hit = m & PERF_MEM_LVL_HIT; 842 miss = m & PERF_MEM_LVL_MISS; 843 844 /* already taken care of */ 845 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS); 846 847 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) { 848 if (!(m & 0x1)) 849 continue; 850 if (l) { 851 strcat(out, " or "); 852 l += 4; 853 } 854 strncat(out, mem_lvl[i], sz - l); 855 l += strlen(mem_lvl[i]); 856 } 857 if (*out == '\0') 858 strcpy(out, "N/A"); 859 if (hit) 860 strncat(out, " hit", sz - l); 861 if (miss) 862 strncat(out, " miss", sz - l); 863 864 return repsep_snprintf(bf, size, "%-*s", width, out); 865 } 866 867 static int64_t 868 sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right) 869 { 870 union perf_mem_data_src data_src_l; 871 union perf_mem_data_src data_src_r; 872 873 if (left->mem_info) 874 data_src_l = left->mem_info->data_src; 875 else 876 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA; 877 878 if (right->mem_info) 879 data_src_r = right->mem_info->data_src; 880 else 881 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA; 882 883 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop); 884 } 885 886 static const char * const snoop_access[] = { 887 "N/A", 888 "None", 889 "Miss", 890 "Hit", 891 "HitM", 892 }; 893 #define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *)) 894 895 static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf, 896 size_t size, unsigned int width) 897 { 898 char out[64]; 899 size_t sz = sizeof(out) - 1; /* -1 for null termination */ 900 size_t i, l = 0; 901 u64 m = PERF_MEM_SNOOP_NA; 902 903 out[0] = '\0'; 904 905 if (he->mem_info) 906 m = he->mem_info->data_src.mem_snoop; 907 908 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) { 909 if (!(m & 0x1)) 910 continue; 911 if (l) { 912 strcat(out, " or "); 913 l += 4; 914 } 915 strncat(out, snoop_access[i], sz - l); 916 l += strlen(snoop_access[i]); 917 } 918 919 if (*out == '\0') 920 strcpy(out, "N/A"); 921 922 return repsep_snprintf(bf, size, "%-*s", width, out); 923 } 924 925 static inline u64 cl_address(u64 address) 926 { 927 /* return the cacheline of the address */ 928 return (address & ~(cacheline_size - 1)); 929 } 930 931 static int64_t 932 sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right) 933 { 934 u64 l, r; 935 struct map *l_map, *r_map; 936 937 if (!left->mem_info) return -1; 938 if (!right->mem_info) return 1; 939 940 /* group event types together */ 941 if (left->cpumode > right->cpumode) return -1; 942 if (left->cpumode < right->cpumode) return 1; 943 944 l_map = left->mem_info->daddr.map; 945 r_map = right->mem_info->daddr.map; 946 947 /* if both are NULL, jump to sort on al_addr instead */ 948 if (!l_map && !r_map) 949 goto addr; 950 951 if (!l_map) return -1; 952 if (!r_map) return 1; 953 954 if (l_map->maj > r_map->maj) return -1; 955 if (l_map->maj < r_map->maj) return 1; 956 957 if (l_map->min > r_map->min) return -1; 958 if (l_map->min < r_map->min) return 1; 959 960 if (l_map->ino > r_map->ino) return -1; 961 if (l_map->ino < r_map->ino) return 1; 962 963 if (l_map->ino_generation > r_map->ino_generation) return -1; 964 if (l_map->ino_generation < r_map->ino_generation) return 1; 965 966 /* 967 * Addresses with no major/minor numbers are assumed to be 968 * anonymous in userspace. Sort those on pid then address. 969 * 970 * The kernel and non-zero major/minor mapped areas are 971 * assumed to be unity mapped. Sort those on address. 972 */ 973 974 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) && 975 (!(l_map->flags & MAP_SHARED)) && 976 !l_map->maj && !l_map->min && !l_map->ino && 977 !l_map->ino_generation) { 978 /* userspace anonymous */ 979 980 if (left->thread->pid_ > right->thread->pid_) return -1; 981 if (left->thread->pid_ < right->thread->pid_) return 1; 982 } 983 984 addr: 985 /* al_addr does all the right addr - start + offset calculations */ 986 l = cl_address(left->mem_info->daddr.al_addr); 987 r = cl_address(right->mem_info->daddr.al_addr); 988 989 if (l > r) return -1; 990 if (l < r) return 1; 991 992 return 0; 993 } 994 995 static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf, 996 size_t size, unsigned int width) 997 { 998 999 uint64_t addr = 0; 1000 struct map *map = NULL; 1001 struct symbol *sym = NULL; 1002 char level = he->level; 1003 1004 if (he->mem_info) { 1005 addr = cl_address(he->mem_info->daddr.al_addr); 1006 map = he->mem_info->daddr.map; 1007 sym = he->mem_info->daddr.sym; 1008 1009 /* print [s] for shared data mmaps */ 1010 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) && 1011 map && (map->type == MAP__VARIABLE) && 1012 (map->flags & MAP_SHARED) && 1013 (map->maj || map->min || map->ino || 1014 map->ino_generation)) 1015 level = 's'; 1016 else if (!map) 1017 level = 'X'; 1018 } 1019 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size, 1020 width); 1021 } 1022 1023 struct sort_entry sort_mispredict = { 1024 .se_header = "Branch Mispredicted", 1025 .se_cmp = sort__mispredict_cmp, 1026 .se_snprintf = hist_entry__mispredict_snprintf, 1027 .se_width_idx = HISTC_MISPREDICT, 1028 }; 1029 1030 static u64 he_weight(struct hist_entry *he) 1031 { 1032 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0; 1033 } 1034 1035 static int64_t 1036 sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right) 1037 { 1038 return he_weight(left) - he_weight(right); 1039 } 1040 1041 static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf, 1042 size_t size, unsigned int width) 1043 { 1044 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he)); 1045 } 1046 1047 struct sort_entry sort_local_weight = { 1048 .se_header = "Local Weight", 1049 .se_cmp = sort__local_weight_cmp, 1050 .se_snprintf = hist_entry__local_weight_snprintf, 1051 .se_width_idx = HISTC_LOCAL_WEIGHT, 1052 }; 1053 1054 static int64_t 1055 sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right) 1056 { 1057 return left->stat.weight - right->stat.weight; 1058 } 1059 1060 static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf, 1061 size_t size, unsigned int width) 1062 { 1063 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight); 1064 } 1065 1066 struct sort_entry sort_global_weight = { 1067 .se_header = "Weight", 1068 .se_cmp = sort__global_weight_cmp, 1069 .se_snprintf = hist_entry__global_weight_snprintf, 1070 .se_width_idx = HISTC_GLOBAL_WEIGHT, 1071 }; 1072 1073 struct sort_entry sort_mem_daddr_sym = { 1074 .se_header = "Data Symbol", 1075 .se_cmp = sort__daddr_cmp, 1076 .se_snprintf = hist_entry__daddr_snprintf, 1077 .se_width_idx = HISTC_MEM_DADDR_SYMBOL, 1078 }; 1079 1080 struct sort_entry sort_mem_daddr_dso = { 1081 .se_header = "Data Object", 1082 .se_cmp = sort__dso_daddr_cmp, 1083 .se_snprintf = hist_entry__dso_daddr_snprintf, 1084 .se_width_idx = HISTC_MEM_DADDR_SYMBOL, 1085 }; 1086 1087 struct sort_entry sort_mem_locked = { 1088 .se_header = "Locked", 1089 .se_cmp = sort__locked_cmp, 1090 .se_snprintf = hist_entry__locked_snprintf, 1091 .se_width_idx = HISTC_MEM_LOCKED, 1092 }; 1093 1094 struct sort_entry sort_mem_tlb = { 1095 .se_header = "TLB access", 1096 .se_cmp = sort__tlb_cmp, 1097 .se_snprintf = hist_entry__tlb_snprintf, 1098 .se_width_idx = HISTC_MEM_TLB, 1099 }; 1100 1101 struct sort_entry sort_mem_lvl = { 1102 .se_header = "Memory access", 1103 .se_cmp = sort__lvl_cmp, 1104 .se_snprintf = hist_entry__lvl_snprintf, 1105 .se_width_idx = HISTC_MEM_LVL, 1106 }; 1107 1108 struct sort_entry sort_mem_snoop = { 1109 .se_header = "Snoop", 1110 .se_cmp = sort__snoop_cmp, 1111 .se_snprintf = hist_entry__snoop_snprintf, 1112 .se_width_idx = HISTC_MEM_SNOOP, 1113 }; 1114 1115 struct sort_entry sort_mem_dcacheline = { 1116 .se_header = "Data Cacheline", 1117 .se_cmp = sort__dcacheline_cmp, 1118 .se_snprintf = hist_entry__dcacheline_snprintf, 1119 .se_width_idx = HISTC_MEM_DCACHELINE, 1120 }; 1121 1122 static int64_t 1123 sort__abort_cmp(struct hist_entry *left, struct hist_entry *right) 1124 { 1125 if (!left->branch_info || !right->branch_info) 1126 return cmp_null(left->branch_info, right->branch_info); 1127 1128 return left->branch_info->flags.abort != 1129 right->branch_info->flags.abort; 1130 } 1131 1132 static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf, 1133 size_t size, unsigned int width) 1134 { 1135 static const char *out = "N/A"; 1136 1137 if (he->branch_info) { 1138 if (he->branch_info->flags.abort) 1139 out = "A"; 1140 else 1141 out = "."; 1142 } 1143 1144 return repsep_snprintf(bf, size, "%-*s", width, out); 1145 } 1146 1147 struct sort_entry sort_abort = { 1148 .se_header = "Transaction abort", 1149 .se_cmp = sort__abort_cmp, 1150 .se_snprintf = hist_entry__abort_snprintf, 1151 .se_width_idx = HISTC_ABORT, 1152 }; 1153 1154 static int64_t 1155 sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right) 1156 { 1157 if (!left->branch_info || !right->branch_info) 1158 return cmp_null(left->branch_info, right->branch_info); 1159 1160 return left->branch_info->flags.in_tx != 1161 right->branch_info->flags.in_tx; 1162 } 1163 1164 static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf, 1165 size_t size, unsigned int width) 1166 { 1167 static const char *out = "N/A"; 1168 1169 if (he->branch_info) { 1170 if (he->branch_info->flags.in_tx) 1171 out = "T"; 1172 else 1173 out = "."; 1174 } 1175 1176 return repsep_snprintf(bf, size, "%-*s", width, out); 1177 } 1178 1179 struct sort_entry sort_in_tx = { 1180 .se_header = "Branch in transaction", 1181 .se_cmp = sort__in_tx_cmp, 1182 .se_snprintf = hist_entry__in_tx_snprintf, 1183 .se_width_idx = HISTC_IN_TX, 1184 }; 1185 1186 static int64_t 1187 sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right) 1188 { 1189 return left->transaction - right->transaction; 1190 } 1191 1192 static inline char *add_str(char *p, const char *str) 1193 { 1194 strcpy(p, str); 1195 return p + strlen(str); 1196 } 1197 1198 static struct txbit { 1199 unsigned flag; 1200 const char *name; 1201 int skip_for_len; 1202 } txbits[] = { 1203 { PERF_TXN_ELISION, "EL ", 0 }, 1204 { PERF_TXN_TRANSACTION, "TX ", 1 }, 1205 { PERF_TXN_SYNC, "SYNC ", 1 }, 1206 { PERF_TXN_ASYNC, "ASYNC ", 0 }, 1207 { PERF_TXN_RETRY, "RETRY ", 0 }, 1208 { PERF_TXN_CONFLICT, "CON ", 0 }, 1209 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 }, 1210 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 }, 1211 { 0, NULL, 0 } 1212 }; 1213 1214 int hist_entry__transaction_len(void) 1215 { 1216 int i; 1217 int len = 0; 1218 1219 for (i = 0; txbits[i].name; i++) { 1220 if (!txbits[i].skip_for_len) 1221 len += strlen(txbits[i].name); 1222 } 1223 len += 4; /* :XX<space> */ 1224 return len; 1225 } 1226 1227 static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf, 1228 size_t size, unsigned int width) 1229 { 1230 u64 t = he->transaction; 1231 char buf[128]; 1232 char *p = buf; 1233 int i; 1234 1235 buf[0] = 0; 1236 for (i = 0; txbits[i].name; i++) 1237 if (txbits[i].flag & t) 1238 p = add_str(p, txbits[i].name); 1239 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC))) 1240 p = add_str(p, "NEITHER "); 1241 if (t & PERF_TXN_ABORT_MASK) { 1242 sprintf(p, ":%" PRIx64, 1243 (t & PERF_TXN_ABORT_MASK) >> 1244 PERF_TXN_ABORT_SHIFT); 1245 p += strlen(p); 1246 } 1247 1248 return repsep_snprintf(bf, size, "%-*s", width, buf); 1249 } 1250 1251 struct sort_entry sort_transaction = { 1252 .se_header = "Transaction ", 1253 .se_cmp = sort__transaction_cmp, 1254 .se_snprintf = hist_entry__transaction_snprintf, 1255 .se_width_idx = HISTC_TRANSACTION, 1256 }; 1257 1258 struct sort_dimension { 1259 const char *name; 1260 struct sort_entry *entry; 1261 int taken; 1262 }; 1263 1264 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) } 1265 1266 static struct sort_dimension common_sort_dimensions[] = { 1267 DIM(SORT_PID, "pid", sort_thread), 1268 DIM(SORT_COMM, "comm", sort_comm), 1269 DIM(SORT_DSO, "dso", sort_dso), 1270 DIM(SORT_SYM, "symbol", sort_sym), 1271 DIM(SORT_PARENT, "parent", sort_parent), 1272 DIM(SORT_CPU, "cpu", sort_cpu), 1273 DIM(SORT_SOCKET, "socket", sort_socket), 1274 DIM(SORT_SRCLINE, "srcline", sort_srcline), 1275 DIM(SORT_SRCFILE, "srcfile", sort_srcfile), 1276 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), 1277 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), 1278 DIM(SORT_TRANSACTION, "transaction", sort_transaction), 1279 }; 1280 1281 #undef DIM 1282 1283 #define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) } 1284 1285 static struct sort_dimension bstack_sort_dimensions[] = { 1286 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from), 1287 DIM(SORT_DSO_TO, "dso_to", sort_dso_to), 1288 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from), 1289 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to), 1290 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict), 1291 DIM(SORT_IN_TX, "in_tx", sort_in_tx), 1292 DIM(SORT_ABORT, "abort", sort_abort), 1293 DIM(SORT_CYCLES, "cycles", sort_cycles), 1294 }; 1295 1296 #undef DIM 1297 1298 #define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) } 1299 1300 static struct sort_dimension memory_sort_dimensions[] = { 1301 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym), 1302 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso), 1303 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked), 1304 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb), 1305 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), 1306 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop), 1307 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline), 1308 }; 1309 1310 #undef DIM 1311 1312 struct hpp_dimension { 1313 const char *name; 1314 struct perf_hpp_fmt *fmt; 1315 int taken; 1316 }; 1317 1318 #define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], } 1319 1320 static struct hpp_dimension hpp_sort_dimensions[] = { 1321 DIM(PERF_HPP__OVERHEAD, "overhead"), 1322 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"), 1323 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"), 1324 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"), 1325 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"), 1326 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"), 1327 DIM(PERF_HPP__SAMPLES, "sample"), 1328 DIM(PERF_HPP__PERIOD, "period"), 1329 }; 1330 1331 #undef DIM 1332 1333 struct hpp_sort_entry { 1334 struct perf_hpp_fmt hpp; 1335 struct sort_entry *se; 1336 }; 1337 1338 bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) 1339 { 1340 struct hpp_sort_entry *hse_a; 1341 struct hpp_sort_entry *hse_b; 1342 1343 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b)) 1344 return false; 1345 1346 hse_a = container_of(a, struct hpp_sort_entry, hpp); 1347 hse_b = container_of(b, struct hpp_sort_entry, hpp); 1348 1349 return hse_a->se == hse_b->se; 1350 } 1351 1352 void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists) 1353 { 1354 struct hpp_sort_entry *hse; 1355 1356 if (!perf_hpp__is_sort_entry(fmt)) 1357 return; 1358 1359 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1360 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name)); 1361 } 1362 1363 static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 1364 struct perf_evsel *evsel) 1365 { 1366 struct hpp_sort_entry *hse; 1367 size_t len = fmt->user_len; 1368 1369 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1370 1371 if (!len) 1372 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx); 1373 1374 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name); 1375 } 1376 1377 static int __sort__hpp_width(struct perf_hpp_fmt *fmt, 1378 struct perf_hpp *hpp __maybe_unused, 1379 struct perf_evsel *evsel) 1380 { 1381 struct hpp_sort_entry *hse; 1382 size_t len = fmt->user_len; 1383 1384 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1385 1386 if (!len) 1387 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx); 1388 1389 return len; 1390 } 1391 1392 static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 1393 struct hist_entry *he) 1394 { 1395 struct hpp_sort_entry *hse; 1396 size_t len = fmt->user_len; 1397 1398 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1399 1400 if (!len) 1401 len = hists__col_len(he->hists, hse->se->se_width_idx); 1402 1403 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len); 1404 } 1405 1406 static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt, 1407 struct hist_entry *a, struct hist_entry *b) 1408 { 1409 struct hpp_sort_entry *hse; 1410 1411 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1412 return hse->se->se_cmp(a, b); 1413 } 1414 1415 static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt, 1416 struct hist_entry *a, struct hist_entry *b) 1417 { 1418 struct hpp_sort_entry *hse; 1419 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *); 1420 1421 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1422 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp; 1423 return collapse_fn(a, b); 1424 } 1425 1426 static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt, 1427 struct hist_entry *a, struct hist_entry *b) 1428 { 1429 struct hpp_sort_entry *hse; 1430 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *); 1431 1432 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1433 sort_fn = hse->se->se_sort ?: hse->se->se_cmp; 1434 return sort_fn(a, b); 1435 } 1436 1437 static struct hpp_sort_entry * 1438 __sort_dimension__alloc_hpp(struct sort_dimension *sd) 1439 { 1440 struct hpp_sort_entry *hse; 1441 1442 hse = malloc(sizeof(*hse)); 1443 if (hse == NULL) { 1444 pr_err("Memory allocation failed\n"); 1445 return NULL; 1446 } 1447 1448 hse->se = sd->entry; 1449 hse->hpp.name = sd->entry->se_header; 1450 hse->hpp.header = __sort__hpp_header; 1451 hse->hpp.width = __sort__hpp_width; 1452 hse->hpp.entry = __sort__hpp_entry; 1453 hse->hpp.color = NULL; 1454 1455 hse->hpp.cmp = __sort__hpp_cmp; 1456 hse->hpp.collapse = __sort__hpp_collapse; 1457 hse->hpp.sort = __sort__hpp_sort; 1458 1459 INIT_LIST_HEAD(&hse->hpp.list); 1460 INIT_LIST_HEAD(&hse->hpp.sort_list); 1461 hse->hpp.elide = false; 1462 hse->hpp.len = 0; 1463 hse->hpp.user_len = 0; 1464 1465 return hse; 1466 } 1467 1468 bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format) 1469 { 1470 return format->header == __sort__hpp_header; 1471 } 1472 1473 static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd) 1474 { 1475 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd); 1476 1477 if (hse == NULL) 1478 return -1; 1479 1480 perf_hpp__register_sort_field(&hse->hpp); 1481 return 0; 1482 } 1483 1484 static int __sort_dimension__add_hpp_output(struct sort_dimension *sd) 1485 { 1486 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd); 1487 1488 if (hse == NULL) 1489 return -1; 1490 1491 perf_hpp__column_register(&hse->hpp); 1492 return 0; 1493 } 1494 1495 static int __sort_dimension__add(struct sort_dimension *sd) 1496 { 1497 if (sd->taken) 1498 return 0; 1499 1500 if (__sort_dimension__add_hpp_sort(sd) < 0) 1501 return -1; 1502 1503 if (sd->entry->se_collapse) 1504 sort__need_collapse = 1; 1505 1506 sd->taken = 1; 1507 1508 return 0; 1509 } 1510 1511 static int __hpp_dimension__add(struct hpp_dimension *hd) 1512 { 1513 if (!hd->taken) { 1514 hd->taken = 1; 1515 1516 perf_hpp__register_sort_field(hd->fmt); 1517 } 1518 return 0; 1519 } 1520 1521 static int __sort_dimension__add_output(struct sort_dimension *sd) 1522 { 1523 if (sd->taken) 1524 return 0; 1525 1526 if (__sort_dimension__add_hpp_output(sd) < 0) 1527 return -1; 1528 1529 sd->taken = 1; 1530 return 0; 1531 } 1532 1533 static int __hpp_dimension__add_output(struct hpp_dimension *hd) 1534 { 1535 if (!hd->taken) { 1536 hd->taken = 1; 1537 1538 perf_hpp__column_register(hd->fmt); 1539 } 1540 return 0; 1541 } 1542 1543 int sort_dimension__add(const char *tok) 1544 { 1545 unsigned int i; 1546 1547 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) { 1548 struct sort_dimension *sd = &common_sort_dimensions[i]; 1549 1550 if (strncasecmp(tok, sd->name, strlen(tok))) 1551 continue; 1552 1553 if (sd->entry == &sort_parent) { 1554 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); 1555 if (ret) { 1556 char err[BUFSIZ]; 1557 1558 regerror(ret, &parent_regex, err, sizeof(err)); 1559 pr_err("Invalid regex: %s\n%s", parent_pattern, err); 1560 return -EINVAL; 1561 } 1562 sort__has_parent = 1; 1563 } else if (sd->entry == &sort_sym) { 1564 sort__has_sym = 1; 1565 /* 1566 * perf diff displays the performance difference amongst 1567 * two or more perf.data files. Those files could come 1568 * from different binaries. So we should not compare 1569 * their ips, but the name of symbol. 1570 */ 1571 if (sort__mode == SORT_MODE__DIFF) 1572 sd->entry->se_collapse = sort__sym_sort; 1573 1574 } else if (sd->entry == &sort_dso) { 1575 sort__has_dso = 1; 1576 } else if (sd->entry == &sort_socket) { 1577 sort__has_socket = 1; 1578 } 1579 1580 return __sort_dimension__add(sd); 1581 } 1582 1583 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { 1584 struct hpp_dimension *hd = &hpp_sort_dimensions[i]; 1585 1586 if (strncasecmp(tok, hd->name, strlen(tok))) 1587 continue; 1588 1589 return __hpp_dimension__add(hd); 1590 } 1591 1592 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 1593 struct sort_dimension *sd = &bstack_sort_dimensions[i]; 1594 1595 if (strncasecmp(tok, sd->name, strlen(tok))) 1596 continue; 1597 1598 if (sort__mode != SORT_MODE__BRANCH) 1599 return -EINVAL; 1600 1601 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) 1602 sort__has_sym = 1; 1603 1604 __sort_dimension__add(sd); 1605 return 0; 1606 } 1607 1608 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) { 1609 struct sort_dimension *sd = &memory_sort_dimensions[i]; 1610 1611 if (strncasecmp(tok, sd->name, strlen(tok))) 1612 continue; 1613 1614 if (sort__mode != SORT_MODE__MEMORY) 1615 return -EINVAL; 1616 1617 if (sd->entry == &sort_mem_daddr_sym) 1618 sort__has_sym = 1; 1619 1620 __sort_dimension__add(sd); 1621 return 0; 1622 } 1623 1624 return -ESRCH; 1625 } 1626 1627 static const char *get_default_sort_order(void) 1628 { 1629 const char *default_sort_orders[] = { 1630 default_sort_order, 1631 default_branch_sort_order, 1632 default_mem_sort_order, 1633 default_top_sort_order, 1634 default_diff_sort_order, 1635 }; 1636 1637 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders)); 1638 1639 return default_sort_orders[sort__mode]; 1640 } 1641 1642 static int setup_sort_order(void) 1643 { 1644 char *new_sort_order; 1645 1646 /* 1647 * Append '+'-prefixed sort order to the default sort 1648 * order string. 1649 */ 1650 if (!sort_order || is_strict_order(sort_order)) 1651 return 0; 1652 1653 if (sort_order[1] == '\0') { 1654 error("Invalid --sort key: `+'"); 1655 return -EINVAL; 1656 } 1657 1658 /* 1659 * We allocate new sort_order string, but we never free it, 1660 * because it's checked over the rest of the code. 1661 */ 1662 if (asprintf(&new_sort_order, "%s,%s", 1663 get_default_sort_order(), sort_order + 1) < 0) { 1664 error("Not enough memory to set up --sort"); 1665 return -ENOMEM; 1666 } 1667 1668 sort_order = new_sort_order; 1669 return 0; 1670 } 1671 1672 static int __setup_sorting(void) 1673 { 1674 char *tmp, *tok, *str; 1675 const char *sort_keys; 1676 int ret = 0; 1677 1678 ret = setup_sort_order(); 1679 if (ret) 1680 return ret; 1681 1682 sort_keys = sort_order; 1683 if (sort_keys == NULL) { 1684 if (is_strict_order(field_order)) { 1685 /* 1686 * If user specified field order but no sort order, 1687 * we'll honor it and not add default sort orders. 1688 */ 1689 return 0; 1690 } 1691 1692 sort_keys = get_default_sort_order(); 1693 } 1694 1695 str = strdup(sort_keys); 1696 if (str == NULL) { 1697 error("Not enough memory to setup sort keys"); 1698 return -ENOMEM; 1699 } 1700 1701 for (tok = strtok_r(str, ", ", &tmp); 1702 tok; tok = strtok_r(NULL, ", ", &tmp)) { 1703 ret = sort_dimension__add(tok); 1704 if (ret == -EINVAL) { 1705 error("Invalid --sort key: `%s'", tok); 1706 break; 1707 } else if (ret == -ESRCH) { 1708 error("Unknown --sort key: `%s'", tok); 1709 break; 1710 } 1711 } 1712 1713 free(str); 1714 return ret; 1715 } 1716 1717 void perf_hpp__set_elide(int idx, bool elide) 1718 { 1719 struct perf_hpp_fmt *fmt; 1720 struct hpp_sort_entry *hse; 1721 1722 perf_hpp__for_each_format(fmt) { 1723 if (!perf_hpp__is_sort_entry(fmt)) 1724 continue; 1725 1726 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1727 if (hse->se->se_width_idx == idx) { 1728 fmt->elide = elide; 1729 break; 1730 } 1731 } 1732 } 1733 1734 static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp) 1735 { 1736 if (list && strlist__nr_entries(list) == 1) { 1737 if (fp != NULL) 1738 fprintf(fp, "# %s: %s\n", list_name, 1739 strlist__entry(list, 0)->s); 1740 return true; 1741 } 1742 return false; 1743 } 1744 1745 static bool get_elide(int idx, FILE *output) 1746 { 1747 switch (idx) { 1748 case HISTC_SYMBOL: 1749 return __get_elide(symbol_conf.sym_list, "symbol", output); 1750 case HISTC_DSO: 1751 return __get_elide(symbol_conf.dso_list, "dso", output); 1752 case HISTC_COMM: 1753 return __get_elide(symbol_conf.comm_list, "comm", output); 1754 default: 1755 break; 1756 } 1757 1758 if (sort__mode != SORT_MODE__BRANCH) 1759 return false; 1760 1761 switch (idx) { 1762 case HISTC_SYMBOL_FROM: 1763 return __get_elide(symbol_conf.sym_from_list, "sym_from", output); 1764 case HISTC_SYMBOL_TO: 1765 return __get_elide(symbol_conf.sym_to_list, "sym_to", output); 1766 case HISTC_DSO_FROM: 1767 return __get_elide(symbol_conf.dso_from_list, "dso_from", output); 1768 case HISTC_DSO_TO: 1769 return __get_elide(symbol_conf.dso_to_list, "dso_to", output); 1770 default: 1771 break; 1772 } 1773 1774 return false; 1775 } 1776 1777 void sort__setup_elide(FILE *output) 1778 { 1779 struct perf_hpp_fmt *fmt; 1780 struct hpp_sort_entry *hse; 1781 1782 perf_hpp__for_each_format(fmt) { 1783 if (!perf_hpp__is_sort_entry(fmt)) 1784 continue; 1785 1786 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1787 fmt->elide = get_elide(hse->se->se_width_idx, output); 1788 } 1789 1790 /* 1791 * It makes no sense to elide all of sort entries. 1792 * Just revert them to show up again. 1793 */ 1794 perf_hpp__for_each_format(fmt) { 1795 if (!perf_hpp__is_sort_entry(fmt)) 1796 continue; 1797 1798 if (!fmt->elide) 1799 return; 1800 } 1801 1802 perf_hpp__for_each_format(fmt) { 1803 if (!perf_hpp__is_sort_entry(fmt)) 1804 continue; 1805 1806 fmt->elide = false; 1807 } 1808 } 1809 1810 static int output_field_add(char *tok) 1811 { 1812 unsigned int i; 1813 1814 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) { 1815 struct sort_dimension *sd = &common_sort_dimensions[i]; 1816 1817 if (strncasecmp(tok, sd->name, strlen(tok))) 1818 continue; 1819 1820 return __sort_dimension__add_output(sd); 1821 } 1822 1823 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { 1824 struct hpp_dimension *hd = &hpp_sort_dimensions[i]; 1825 1826 if (strncasecmp(tok, hd->name, strlen(tok))) 1827 continue; 1828 1829 return __hpp_dimension__add_output(hd); 1830 } 1831 1832 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 1833 struct sort_dimension *sd = &bstack_sort_dimensions[i]; 1834 1835 if (strncasecmp(tok, sd->name, strlen(tok))) 1836 continue; 1837 1838 return __sort_dimension__add_output(sd); 1839 } 1840 1841 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) { 1842 struct sort_dimension *sd = &memory_sort_dimensions[i]; 1843 1844 if (strncasecmp(tok, sd->name, strlen(tok))) 1845 continue; 1846 1847 return __sort_dimension__add_output(sd); 1848 } 1849 1850 return -ESRCH; 1851 } 1852 1853 static void reset_dimensions(void) 1854 { 1855 unsigned int i; 1856 1857 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) 1858 common_sort_dimensions[i].taken = 0; 1859 1860 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) 1861 hpp_sort_dimensions[i].taken = 0; 1862 1863 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) 1864 bstack_sort_dimensions[i].taken = 0; 1865 1866 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) 1867 memory_sort_dimensions[i].taken = 0; 1868 } 1869 1870 bool is_strict_order(const char *order) 1871 { 1872 return order && (*order != '+'); 1873 } 1874 1875 static int __setup_output_field(void) 1876 { 1877 char *tmp, *tok, *str, *strp; 1878 int ret = -EINVAL; 1879 1880 if (field_order == NULL) 1881 return 0; 1882 1883 reset_dimensions(); 1884 1885 strp = str = strdup(field_order); 1886 if (str == NULL) { 1887 error("Not enough memory to setup output fields"); 1888 return -ENOMEM; 1889 } 1890 1891 if (!is_strict_order(field_order)) 1892 strp++; 1893 1894 if (!strlen(strp)) { 1895 error("Invalid --fields key: `+'"); 1896 goto out; 1897 } 1898 1899 for (tok = strtok_r(strp, ", ", &tmp); 1900 tok; tok = strtok_r(NULL, ", ", &tmp)) { 1901 ret = output_field_add(tok); 1902 if (ret == -EINVAL) { 1903 error("Invalid --fields key: `%s'", tok); 1904 break; 1905 } else if (ret == -ESRCH) { 1906 error("Unknown --fields key: `%s'", tok); 1907 break; 1908 } 1909 } 1910 1911 out: 1912 free(str); 1913 return ret; 1914 } 1915 1916 int setup_sorting(void) 1917 { 1918 int err; 1919 1920 err = __setup_sorting(); 1921 if (err < 0) 1922 return err; 1923 1924 if (parent_pattern != default_parent_pattern) { 1925 err = sort_dimension__add("parent"); 1926 if (err < 0) 1927 return err; 1928 } 1929 1930 reset_dimensions(); 1931 1932 /* 1933 * perf diff doesn't use default hpp output fields. 1934 */ 1935 if (sort__mode != SORT_MODE__DIFF) 1936 perf_hpp__init(); 1937 1938 err = __setup_output_field(); 1939 if (err < 0) 1940 return err; 1941 1942 /* copy sort keys to output fields */ 1943 perf_hpp__setup_output_field(); 1944 /* and then copy output fields to sort keys */ 1945 perf_hpp__append_sort_keys(); 1946 1947 return 0; 1948 } 1949 1950 void reset_output_field(void) 1951 { 1952 sort__need_collapse = 0; 1953 sort__has_parent = 0; 1954 sort__has_sym = 0; 1955 sort__has_dso = 0; 1956 1957 field_order = NULL; 1958 sort_order = NULL; 1959 1960 reset_dimensions(); 1961 perf_hpp__reset_output_field(); 1962 } 1963