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__iaddr_cmp(struct hist_entry *left, struct hist_entry *right) 659 { 660 uint64_t l = 0, r = 0; 661 662 if (left->mem_info) 663 l = left->mem_info->iaddr.addr; 664 if (right->mem_info) 665 r = right->mem_info->iaddr.addr; 666 667 return (int64_t)(r - l); 668 } 669 670 static int hist_entry__iaddr_snprintf(struct hist_entry *he, char *bf, 671 size_t size, unsigned int width) 672 { 673 uint64_t addr = 0; 674 struct map *map = NULL; 675 struct symbol *sym = NULL; 676 677 if (he->mem_info) { 678 addr = he->mem_info->iaddr.addr; 679 map = he->mem_info->iaddr.map; 680 sym = he->mem_info->iaddr.sym; 681 } 682 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size, 683 width); 684 } 685 686 static int64_t 687 sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right) 688 { 689 struct map *map_l = NULL; 690 struct map *map_r = NULL; 691 692 if (left->mem_info) 693 map_l = left->mem_info->daddr.map; 694 if (right->mem_info) 695 map_r = right->mem_info->daddr.map; 696 697 return _sort__dso_cmp(map_l, map_r); 698 } 699 700 static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf, 701 size_t size, unsigned int width) 702 { 703 struct map *map = NULL; 704 705 if (he->mem_info) 706 map = he->mem_info->daddr.map; 707 708 return _hist_entry__dso_snprintf(map, bf, size, width); 709 } 710 711 static int64_t 712 sort__locked_cmp(struct hist_entry *left, struct hist_entry *right) 713 { 714 union perf_mem_data_src data_src_l; 715 union perf_mem_data_src data_src_r; 716 717 if (left->mem_info) 718 data_src_l = left->mem_info->data_src; 719 else 720 data_src_l.mem_lock = PERF_MEM_LOCK_NA; 721 722 if (right->mem_info) 723 data_src_r = right->mem_info->data_src; 724 else 725 data_src_r.mem_lock = PERF_MEM_LOCK_NA; 726 727 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock); 728 } 729 730 static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf, 731 size_t size, unsigned int width) 732 { 733 const char *out; 734 u64 mask = PERF_MEM_LOCK_NA; 735 736 if (he->mem_info) 737 mask = he->mem_info->data_src.mem_lock; 738 739 if (mask & PERF_MEM_LOCK_NA) 740 out = "N/A"; 741 else if (mask & PERF_MEM_LOCK_LOCKED) 742 out = "Yes"; 743 else 744 out = "No"; 745 746 return repsep_snprintf(bf, size, "%-*s", width, out); 747 } 748 749 static int64_t 750 sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right) 751 { 752 union perf_mem_data_src data_src_l; 753 union perf_mem_data_src data_src_r; 754 755 if (left->mem_info) 756 data_src_l = left->mem_info->data_src; 757 else 758 data_src_l.mem_dtlb = PERF_MEM_TLB_NA; 759 760 if (right->mem_info) 761 data_src_r = right->mem_info->data_src; 762 else 763 data_src_r.mem_dtlb = PERF_MEM_TLB_NA; 764 765 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb); 766 } 767 768 static const char * const tlb_access[] = { 769 "N/A", 770 "HIT", 771 "MISS", 772 "L1", 773 "L2", 774 "Walker", 775 "Fault", 776 }; 777 #define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *)) 778 779 static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf, 780 size_t size, unsigned int width) 781 { 782 char out[64]; 783 size_t sz = sizeof(out) - 1; /* -1 for null termination */ 784 size_t l = 0, i; 785 u64 m = PERF_MEM_TLB_NA; 786 u64 hit, miss; 787 788 out[0] = '\0'; 789 790 if (he->mem_info) 791 m = he->mem_info->data_src.mem_dtlb; 792 793 hit = m & PERF_MEM_TLB_HIT; 794 miss = m & PERF_MEM_TLB_MISS; 795 796 /* already taken care of */ 797 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS); 798 799 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) { 800 if (!(m & 0x1)) 801 continue; 802 if (l) { 803 strcat(out, " or "); 804 l += 4; 805 } 806 strncat(out, tlb_access[i], sz - l); 807 l += strlen(tlb_access[i]); 808 } 809 if (*out == '\0') 810 strcpy(out, "N/A"); 811 if (hit) 812 strncat(out, " hit", sz - l); 813 if (miss) 814 strncat(out, " miss", sz - l); 815 816 return repsep_snprintf(bf, size, "%-*s", width, out); 817 } 818 819 static int64_t 820 sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right) 821 { 822 union perf_mem_data_src data_src_l; 823 union perf_mem_data_src data_src_r; 824 825 if (left->mem_info) 826 data_src_l = left->mem_info->data_src; 827 else 828 data_src_l.mem_lvl = PERF_MEM_LVL_NA; 829 830 if (right->mem_info) 831 data_src_r = right->mem_info->data_src; 832 else 833 data_src_r.mem_lvl = PERF_MEM_LVL_NA; 834 835 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl); 836 } 837 838 static const char * const mem_lvl[] = { 839 "N/A", 840 "HIT", 841 "MISS", 842 "L1", 843 "LFB", 844 "L2", 845 "L3", 846 "Local RAM", 847 "Remote RAM (1 hop)", 848 "Remote RAM (2 hops)", 849 "Remote Cache (1 hop)", 850 "Remote Cache (2 hops)", 851 "I/O", 852 "Uncached", 853 }; 854 #define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *)) 855 856 static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf, 857 size_t size, unsigned int width) 858 { 859 char out[64]; 860 size_t sz = sizeof(out) - 1; /* -1 for null termination */ 861 size_t i, l = 0; 862 u64 m = PERF_MEM_LVL_NA; 863 u64 hit, miss; 864 865 if (he->mem_info) 866 m = he->mem_info->data_src.mem_lvl; 867 868 out[0] = '\0'; 869 870 hit = m & PERF_MEM_LVL_HIT; 871 miss = m & PERF_MEM_LVL_MISS; 872 873 /* already taken care of */ 874 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS); 875 876 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) { 877 if (!(m & 0x1)) 878 continue; 879 if (l) { 880 strcat(out, " or "); 881 l += 4; 882 } 883 strncat(out, mem_lvl[i], sz - l); 884 l += strlen(mem_lvl[i]); 885 } 886 if (*out == '\0') 887 strcpy(out, "N/A"); 888 if (hit) 889 strncat(out, " hit", sz - l); 890 if (miss) 891 strncat(out, " miss", sz - l); 892 893 return repsep_snprintf(bf, size, "%-*s", width, out); 894 } 895 896 static int64_t 897 sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right) 898 { 899 union perf_mem_data_src data_src_l; 900 union perf_mem_data_src data_src_r; 901 902 if (left->mem_info) 903 data_src_l = left->mem_info->data_src; 904 else 905 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA; 906 907 if (right->mem_info) 908 data_src_r = right->mem_info->data_src; 909 else 910 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA; 911 912 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop); 913 } 914 915 static const char * const snoop_access[] = { 916 "N/A", 917 "None", 918 "Miss", 919 "Hit", 920 "HitM", 921 }; 922 #define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *)) 923 924 static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf, 925 size_t size, unsigned int width) 926 { 927 char out[64]; 928 size_t sz = sizeof(out) - 1; /* -1 for null termination */ 929 size_t i, l = 0; 930 u64 m = PERF_MEM_SNOOP_NA; 931 932 out[0] = '\0'; 933 934 if (he->mem_info) 935 m = he->mem_info->data_src.mem_snoop; 936 937 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) { 938 if (!(m & 0x1)) 939 continue; 940 if (l) { 941 strcat(out, " or "); 942 l += 4; 943 } 944 strncat(out, snoop_access[i], sz - l); 945 l += strlen(snoop_access[i]); 946 } 947 948 if (*out == '\0') 949 strcpy(out, "N/A"); 950 951 return repsep_snprintf(bf, size, "%-*s", width, out); 952 } 953 954 static inline u64 cl_address(u64 address) 955 { 956 /* return the cacheline of the address */ 957 return (address & ~(cacheline_size - 1)); 958 } 959 960 static int64_t 961 sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right) 962 { 963 u64 l, r; 964 struct map *l_map, *r_map; 965 966 if (!left->mem_info) return -1; 967 if (!right->mem_info) return 1; 968 969 /* group event types together */ 970 if (left->cpumode > right->cpumode) return -1; 971 if (left->cpumode < right->cpumode) return 1; 972 973 l_map = left->mem_info->daddr.map; 974 r_map = right->mem_info->daddr.map; 975 976 /* if both are NULL, jump to sort on al_addr instead */ 977 if (!l_map && !r_map) 978 goto addr; 979 980 if (!l_map) return -1; 981 if (!r_map) return 1; 982 983 if (l_map->maj > r_map->maj) return -1; 984 if (l_map->maj < r_map->maj) return 1; 985 986 if (l_map->min > r_map->min) return -1; 987 if (l_map->min < r_map->min) return 1; 988 989 if (l_map->ino > r_map->ino) return -1; 990 if (l_map->ino < r_map->ino) return 1; 991 992 if (l_map->ino_generation > r_map->ino_generation) return -1; 993 if (l_map->ino_generation < r_map->ino_generation) return 1; 994 995 /* 996 * Addresses with no major/minor numbers are assumed to be 997 * anonymous in userspace. Sort those on pid then address. 998 * 999 * The kernel and non-zero major/minor mapped areas are 1000 * assumed to be unity mapped. Sort those on address. 1001 */ 1002 1003 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) && 1004 (!(l_map->flags & MAP_SHARED)) && 1005 !l_map->maj && !l_map->min && !l_map->ino && 1006 !l_map->ino_generation) { 1007 /* userspace anonymous */ 1008 1009 if (left->thread->pid_ > right->thread->pid_) return -1; 1010 if (left->thread->pid_ < right->thread->pid_) return 1; 1011 } 1012 1013 addr: 1014 /* al_addr does all the right addr - start + offset calculations */ 1015 l = cl_address(left->mem_info->daddr.al_addr); 1016 r = cl_address(right->mem_info->daddr.al_addr); 1017 1018 if (l > r) return -1; 1019 if (l < r) return 1; 1020 1021 return 0; 1022 } 1023 1024 static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf, 1025 size_t size, unsigned int width) 1026 { 1027 1028 uint64_t addr = 0; 1029 struct map *map = NULL; 1030 struct symbol *sym = NULL; 1031 char level = he->level; 1032 1033 if (he->mem_info) { 1034 addr = cl_address(he->mem_info->daddr.al_addr); 1035 map = he->mem_info->daddr.map; 1036 sym = he->mem_info->daddr.sym; 1037 1038 /* print [s] for shared data mmaps */ 1039 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) && 1040 map && (map->type == MAP__VARIABLE) && 1041 (map->flags & MAP_SHARED) && 1042 (map->maj || map->min || map->ino || 1043 map->ino_generation)) 1044 level = 's'; 1045 else if (!map) 1046 level = 'X'; 1047 } 1048 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size, 1049 width); 1050 } 1051 1052 struct sort_entry sort_mispredict = { 1053 .se_header = "Branch Mispredicted", 1054 .se_cmp = sort__mispredict_cmp, 1055 .se_snprintf = hist_entry__mispredict_snprintf, 1056 .se_width_idx = HISTC_MISPREDICT, 1057 }; 1058 1059 static u64 he_weight(struct hist_entry *he) 1060 { 1061 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0; 1062 } 1063 1064 static int64_t 1065 sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right) 1066 { 1067 return he_weight(left) - he_weight(right); 1068 } 1069 1070 static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf, 1071 size_t size, unsigned int width) 1072 { 1073 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he)); 1074 } 1075 1076 struct sort_entry sort_local_weight = { 1077 .se_header = "Local Weight", 1078 .se_cmp = sort__local_weight_cmp, 1079 .se_snprintf = hist_entry__local_weight_snprintf, 1080 .se_width_idx = HISTC_LOCAL_WEIGHT, 1081 }; 1082 1083 static int64_t 1084 sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right) 1085 { 1086 return left->stat.weight - right->stat.weight; 1087 } 1088 1089 static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf, 1090 size_t size, unsigned int width) 1091 { 1092 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight); 1093 } 1094 1095 struct sort_entry sort_global_weight = { 1096 .se_header = "Weight", 1097 .se_cmp = sort__global_weight_cmp, 1098 .se_snprintf = hist_entry__global_weight_snprintf, 1099 .se_width_idx = HISTC_GLOBAL_WEIGHT, 1100 }; 1101 1102 struct sort_entry sort_mem_daddr_sym = { 1103 .se_header = "Data Symbol", 1104 .se_cmp = sort__daddr_cmp, 1105 .se_snprintf = hist_entry__daddr_snprintf, 1106 .se_width_idx = HISTC_MEM_DADDR_SYMBOL, 1107 }; 1108 1109 struct sort_entry sort_mem_iaddr_sym = { 1110 .se_header = "Code Symbol", 1111 .se_cmp = sort__iaddr_cmp, 1112 .se_snprintf = hist_entry__iaddr_snprintf, 1113 .se_width_idx = HISTC_MEM_IADDR_SYMBOL, 1114 }; 1115 1116 struct sort_entry sort_mem_daddr_dso = { 1117 .se_header = "Data Object", 1118 .se_cmp = sort__dso_daddr_cmp, 1119 .se_snprintf = hist_entry__dso_daddr_snprintf, 1120 .se_width_idx = HISTC_MEM_DADDR_SYMBOL, 1121 }; 1122 1123 struct sort_entry sort_mem_locked = { 1124 .se_header = "Locked", 1125 .se_cmp = sort__locked_cmp, 1126 .se_snprintf = hist_entry__locked_snprintf, 1127 .se_width_idx = HISTC_MEM_LOCKED, 1128 }; 1129 1130 struct sort_entry sort_mem_tlb = { 1131 .se_header = "TLB access", 1132 .se_cmp = sort__tlb_cmp, 1133 .se_snprintf = hist_entry__tlb_snprintf, 1134 .se_width_idx = HISTC_MEM_TLB, 1135 }; 1136 1137 struct sort_entry sort_mem_lvl = { 1138 .se_header = "Memory access", 1139 .se_cmp = sort__lvl_cmp, 1140 .se_snprintf = hist_entry__lvl_snprintf, 1141 .se_width_idx = HISTC_MEM_LVL, 1142 }; 1143 1144 struct sort_entry sort_mem_snoop = { 1145 .se_header = "Snoop", 1146 .se_cmp = sort__snoop_cmp, 1147 .se_snprintf = hist_entry__snoop_snprintf, 1148 .se_width_idx = HISTC_MEM_SNOOP, 1149 }; 1150 1151 struct sort_entry sort_mem_dcacheline = { 1152 .se_header = "Data Cacheline", 1153 .se_cmp = sort__dcacheline_cmp, 1154 .se_snprintf = hist_entry__dcacheline_snprintf, 1155 .se_width_idx = HISTC_MEM_DCACHELINE, 1156 }; 1157 1158 static int64_t 1159 sort__abort_cmp(struct hist_entry *left, struct hist_entry *right) 1160 { 1161 if (!left->branch_info || !right->branch_info) 1162 return cmp_null(left->branch_info, right->branch_info); 1163 1164 return left->branch_info->flags.abort != 1165 right->branch_info->flags.abort; 1166 } 1167 1168 static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf, 1169 size_t size, unsigned int width) 1170 { 1171 static const char *out = "N/A"; 1172 1173 if (he->branch_info) { 1174 if (he->branch_info->flags.abort) 1175 out = "A"; 1176 else 1177 out = "."; 1178 } 1179 1180 return repsep_snprintf(bf, size, "%-*s", width, out); 1181 } 1182 1183 struct sort_entry sort_abort = { 1184 .se_header = "Transaction abort", 1185 .se_cmp = sort__abort_cmp, 1186 .se_snprintf = hist_entry__abort_snprintf, 1187 .se_width_idx = HISTC_ABORT, 1188 }; 1189 1190 static int64_t 1191 sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right) 1192 { 1193 if (!left->branch_info || !right->branch_info) 1194 return cmp_null(left->branch_info, right->branch_info); 1195 1196 return left->branch_info->flags.in_tx != 1197 right->branch_info->flags.in_tx; 1198 } 1199 1200 static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf, 1201 size_t size, unsigned int width) 1202 { 1203 static const char *out = "N/A"; 1204 1205 if (he->branch_info) { 1206 if (he->branch_info->flags.in_tx) 1207 out = "T"; 1208 else 1209 out = "."; 1210 } 1211 1212 return repsep_snprintf(bf, size, "%-*s", width, out); 1213 } 1214 1215 struct sort_entry sort_in_tx = { 1216 .se_header = "Branch in transaction", 1217 .se_cmp = sort__in_tx_cmp, 1218 .se_snprintf = hist_entry__in_tx_snprintf, 1219 .se_width_idx = HISTC_IN_TX, 1220 }; 1221 1222 static int64_t 1223 sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right) 1224 { 1225 return left->transaction - right->transaction; 1226 } 1227 1228 static inline char *add_str(char *p, const char *str) 1229 { 1230 strcpy(p, str); 1231 return p + strlen(str); 1232 } 1233 1234 static struct txbit { 1235 unsigned flag; 1236 const char *name; 1237 int skip_for_len; 1238 } txbits[] = { 1239 { PERF_TXN_ELISION, "EL ", 0 }, 1240 { PERF_TXN_TRANSACTION, "TX ", 1 }, 1241 { PERF_TXN_SYNC, "SYNC ", 1 }, 1242 { PERF_TXN_ASYNC, "ASYNC ", 0 }, 1243 { PERF_TXN_RETRY, "RETRY ", 0 }, 1244 { PERF_TXN_CONFLICT, "CON ", 0 }, 1245 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 }, 1246 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 }, 1247 { 0, NULL, 0 } 1248 }; 1249 1250 int hist_entry__transaction_len(void) 1251 { 1252 int i; 1253 int len = 0; 1254 1255 for (i = 0; txbits[i].name; i++) { 1256 if (!txbits[i].skip_for_len) 1257 len += strlen(txbits[i].name); 1258 } 1259 len += 4; /* :XX<space> */ 1260 return len; 1261 } 1262 1263 static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf, 1264 size_t size, unsigned int width) 1265 { 1266 u64 t = he->transaction; 1267 char buf[128]; 1268 char *p = buf; 1269 int i; 1270 1271 buf[0] = 0; 1272 for (i = 0; txbits[i].name; i++) 1273 if (txbits[i].flag & t) 1274 p = add_str(p, txbits[i].name); 1275 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC))) 1276 p = add_str(p, "NEITHER "); 1277 if (t & PERF_TXN_ABORT_MASK) { 1278 sprintf(p, ":%" PRIx64, 1279 (t & PERF_TXN_ABORT_MASK) >> 1280 PERF_TXN_ABORT_SHIFT); 1281 p += strlen(p); 1282 } 1283 1284 return repsep_snprintf(bf, size, "%-*s", width, buf); 1285 } 1286 1287 struct sort_entry sort_transaction = { 1288 .se_header = "Transaction ", 1289 .se_cmp = sort__transaction_cmp, 1290 .se_snprintf = hist_entry__transaction_snprintf, 1291 .se_width_idx = HISTC_TRANSACTION, 1292 }; 1293 1294 struct sort_dimension { 1295 const char *name; 1296 struct sort_entry *entry; 1297 int taken; 1298 }; 1299 1300 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) } 1301 1302 static struct sort_dimension common_sort_dimensions[] = { 1303 DIM(SORT_PID, "pid", sort_thread), 1304 DIM(SORT_COMM, "comm", sort_comm), 1305 DIM(SORT_DSO, "dso", sort_dso), 1306 DIM(SORT_SYM, "symbol", sort_sym), 1307 DIM(SORT_PARENT, "parent", sort_parent), 1308 DIM(SORT_CPU, "cpu", sort_cpu), 1309 DIM(SORT_SOCKET, "socket", sort_socket), 1310 DIM(SORT_SRCLINE, "srcline", sort_srcline), 1311 DIM(SORT_SRCFILE, "srcfile", sort_srcfile), 1312 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), 1313 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), 1314 DIM(SORT_TRANSACTION, "transaction", sort_transaction), 1315 }; 1316 1317 #undef DIM 1318 1319 #define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) } 1320 1321 static struct sort_dimension bstack_sort_dimensions[] = { 1322 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from), 1323 DIM(SORT_DSO_TO, "dso_to", sort_dso_to), 1324 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from), 1325 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to), 1326 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict), 1327 DIM(SORT_IN_TX, "in_tx", sort_in_tx), 1328 DIM(SORT_ABORT, "abort", sort_abort), 1329 DIM(SORT_CYCLES, "cycles", sort_cycles), 1330 }; 1331 1332 #undef DIM 1333 1334 #define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) } 1335 1336 static struct sort_dimension memory_sort_dimensions[] = { 1337 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym), 1338 DIM(SORT_MEM_IADDR_SYMBOL, "symbol_iaddr", sort_mem_iaddr_sym), 1339 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso), 1340 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked), 1341 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb), 1342 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), 1343 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop), 1344 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline), 1345 }; 1346 1347 #undef DIM 1348 1349 struct hpp_dimension { 1350 const char *name; 1351 struct perf_hpp_fmt *fmt; 1352 int taken; 1353 }; 1354 1355 #define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], } 1356 1357 static struct hpp_dimension hpp_sort_dimensions[] = { 1358 DIM(PERF_HPP__OVERHEAD, "overhead"), 1359 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"), 1360 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"), 1361 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"), 1362 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"), 1363 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"), 1364 DIM(PERF_HPP__SAMPLES, "sample"), 1365 DIM(PERF_HPP__PERIOD, "period"), 1366 }; 1367 1368 #undef DIM 1369 1370 struct hpp_sort_entry { 1371 struct perf_hpp_fmt hpp; 1372 struct sort_entry *se; 1373 }; 1374 1375 bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) 1376 { 1377 struct hpp_sort_entry *hse_a; 1378 struct hpp_sort_entry *hse_b; 1379 1380 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b)) 1381 return false; 1382 1383 hse_a = container_of(a, struct hpp_sort_entry, hpp); 1384 hse_b = container_of(b, struct hpp_sort_entry, hpp); 1385 1386 return hse_a->se == hse_b->se; 1387 } 1388 1389 void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists) 1390 { 1391 struct hpp_sort_entry *hse; 1392 1393 if (!perf_hpp__is_sort_entry(fmt)) 1394 return; 1395 1396 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1397 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name)); 1398 } 1399 1400 static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 1401 struct perf_evsel *evsel) 1402 { 1403 struct hpp_sort_entry *hse; 1404 size_t len = fmt->user_len; 1405 1406 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1407 1408 if (!len) 1409 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx); 1410 1411 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name); 1412 } 1413 1414 static int __sort__hpp_width(struct perf_hpp_fmt *fmt, 1415 struct perf_hpp *hpp __maybe_unused, 1416 struct perf_evsel *evsel) 1417 { 1418 struct hpp_sort_entry *hse; 1419 size_t len = fmt->user_len; 1420 1421 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1422 1423 if (!len) 1424 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx); 1425 1426 return len; 1427 } 1428 1429 static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 1430 struct hist_entry *he) 1431 { 1432 struct hpp_sort_entry *hse; 1433 size_t len = fmt->user_len; 1434 1435 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1436 1437 if (!len) 1438 len = hists__col_len(he->hists, hse->se->se_width_idx); 1439 1440 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len); 1441 } 1442 1443 static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt, 1444 struct hist_entry *a, struct hist_entry *b) 1445 { 1446 struct hpp_sort_entry *hse; 1447 1448 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1449 return hse->se->se_cmp(a, b); 1450 } 1451 1452 static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt, 1453 struct hist_entry *a, struct hist_entry *b) 1454 { 1455 struct hpp_sort_entry *hse; 1456 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *); 1457 1458 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1459 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp; 1460 return collapse_fn(a, b); 1461 } 1462 1463 static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt, 1464 struct hist_entry *a, struct hist_entry *b) 1465 { 1466 struct hpp_sort_entry *hse; 1467 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *); 1468 1469 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1470 sort_fn = hse->se->se_sort ?: hse->se->se_cmp; 1471 return sort_fn(a, b); 1472 } 1473 1474 static struct hpp_sort_entry * 1475 __sort_dimension__alloc_hpp(struct sort_dimension *sd) 1476 { 1477 struct hpp_sort_entry *hse; 1478 1479 hse = malloc(sizeof(*hse)); 1480 if (hse == NULL) { 1481 pr_err("Memory allocation failed\n"); 1482 return NULL; 1483 } 1484 1485 hse->se = sd->entry; 1486 hse->hpp.name = sd->entry->se_header; 1487 hse->hpp.header = __sort__hpp_header; 1488 hse->hpp.width = __sort__hpp_width; 1489 hse->hpp.entry = __sort__hpp_entry; 1490 hse->hpp.color = NULL; 1491 1492 hse->hpp.cmp = __sort__hpp_cmp; 1493 hse->hpp.collapse = __sort__hpp_collapse; 1494 hse->hpp.sort = __sort__hpp_sort; 1495 1496 INIT_LIST_HEAD(&hse->hpp.list); 1497 INIT_LIST_HEAD(&hse->hpp.sort_list); 1498 hse->hpp.elide = false; 1499 hse->hpp.len = 0; 1500 hse->hpp.user_len = 0; 1501 1502 return hse; 1503 } 1504 1505 bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format) 1506 { 1507 return format->header == __sort__hpp_header; 1508 } 1509 1510 static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd) 1511 { 1512 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd); 1513 1514 if (hse == NULL) 1515 return -1; 1516 1517 perf_hpp__register_sort_field(&hse->hpp); 1518 return 0; 1519 } 1520 1521 static int __sort_dimension__add_hpp_output(struct sort_dimension *sd) 1522 { 1523 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd); 1524 1525 if (hse == NULL) 1526 return -1; 1527 1528 perf_hpp__column_register(&hse->hpp); 1529 return 0; 1530 } 1531 1532 static int __sort_dimension__add(struct sort_dimension *sd) 1533 { 1534 if (sd->taken) 1535 return 0; 1536 1537 if (__sort_dimension__add_hpp_sort(sd) < 0) 1538 return -1; 1539 1540 if (sd->entry->se_collapse) 1541 sort__need_collapse = 1; 1542 1543 sd->taken = 1; 1544 1545 return 0; 1546 } 1547 1548 static int __hpp_dimension__add(struct hpp_dimension *hd) 1549 { 1550 if (!hd->taken) { 1551 hd->taken = 1; 1552 1553 perf_hpp__register_sort_field(hd->fmt); 1554 } 1555 return 0; 1556 } 1557 1558 static int __sort_dimension__add_output(struct sort_dimension *sd) 1559 { 1560 if (sd->taken) 1561 return 0; 1562 1563 if (__sort_dimension__add_hpp_output(sd) < 0) 1564 return -1; 1565 1566 sd->taken = 1; 1567 return 0; 1568 } 1569 1570 static int __hpp_dimension__add_output(struct hpp_dimension *hd) 1571 { 1572 if (!hd->taken) { 1573 hd->taken = 1; 1574 1575 perf_hpp__column_register(hd->fmt); 1576 } 1577 return 0; 1578 } 1579 1580 int hpp_dimension__add_output(unsigned col) 1581 { 1582 BUG_ON(col >= PERF_HPP__MAX_INDEX); 1583 return __hpp_dimension__add_output(&hpp_sort_dimensions[col]); 1584 } 1585 1586 int sort_dimension__add(const char *tok) 1587 { 1588 unsigned int i; 1589 1590 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) { 1591 struct sort_dimension *sd = &common_sort_dimensions[i]; 1592 1593 if (strncasecmp(tok, sd->name, strlen(tok))) 1594 continue; 1595 1596 if (sd->entry == &sort_parent) { 1597 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); 1598 if (ret) { 1599 char err[BUFSIZ]; 1600 1601 regerror(ret, &parent_regex, err, sizeof(err)); 1602 pr_err("Invalid regex: %s\n%s", parent_pattern, err); 1603 return -EINVAL; 1604 } 1605 sort__has_parent = 1; 1606 } else if (sd->entry == &sort_sym) { 1607 sort__has_sym = 1; 1608 /* 1609 * perf diff displays the performance difference amongst 1610 * two or more perf.data files. Those files could come 1611 * from different binaries. So we should not compare 1612 * their ips, but the name of symbol. 1613 */ 1614 if (sort__mode == SORT_MODE__DIFF) 1615 sd->entry->se_collapse = sort__sym_sort; 1616 1617 } else if (sd->entry == &sort_dso) { 1618 sort__has_dso = 1; 1619 } else if (sd->entry == &sort_socket) { 1620 sort__has_socket = 1; 1621 } 1622 1623 return __sort_dimension__add(sd); 1624 } 1625 1626 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { 1627 struct hpp_dimension *hd = &hpp_sort_dimensions[i]; 1628 1629 if (strncasecmp(tok, hd->name, strlen(tok))) 1630 continue; 1631 1632 return __hpp_dimension__add(hd); 1633 } 1634 1635 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 1636 struct sort_dimension *sd = &bstack_sort_dimensions[i]; 1637 1638 if (strncasecmp(tok, sd->name, strlen(tok))) 1639 continue; 1640 1641 if (sort__mode != SORT_MODE__BRANCH) 1642 return -EINVAL; 1643 1644 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) 1645 sort__has_sym = 1; 1646 1647 __sort_dimension__add(sd); 1648 return 0; 1649 } 1650 1651 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) { 1652 struct sort_dimension *sd = &memory_sort_dimensions[i]; 1653 1654 if (strncasecmp(tok, sd->name, strlen(tok))) 1655 continue; 1656 1657 if (sort__mode != SORT_MODE__MEMORY) 1658 return -EINVAL; 1659 1660 if (sd->entry == &sort_mem_daddr_sym) 1661 sort__has_sym = 1; 1662 1663 __sort_dimension__add(sd); 1664 return 0; 1665 } 1666 1667 return -ESRCH; 1668 } 1669 1670 static const char *get_default_sort_order(void) 1671 { 1672 const char *default_sort_orders[] = { 1673 default_sort_order, 1674 default_branch_sort_order, 1675 default_mem_sort_order, 1676 default_top_sort_order, 1677 default_diff_sort_order, 1678 }; 1679 1680 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders)); 1681 1682 return default_sort_orders[sort__mode]; 1683 } 1684 1685 static int setup_sort_order(void) 1686 { 1687 char *new_sort_order; 1688 1689 /* 1690 * Append '+'-prefixed sort order to the default sort 1691 * order string. 1692 */ 1693 if (!sort_order || is_strict_order(sort_order)) 1694 return 0; 1695 1696 if (sort_order[1] == '\0') { 1697 error("Invalid --sort key: `+'"); 1698 return -EINVAL; 1699 } 1700 1701 /* 1702 * We allocate new sort_order string, but we never free it, 1703 * because it's checked over the rest of the code. 1704 */ 1705 if (asprintf(&new_sort_order, "%s,%s", 1706 get_default_sort_order(), sort_order + 1) < 0) { 1707 error("Not enough memory to set up --sort"); 1708 return -ENOMEM; 1709 } 1710 1711 sort_order = new_sort_order; 1712 return 0; 1713 } 1714 1715 static int __setup_sorting(void) 1716 { 1717 char *tmp, *tok, *str; 1718 const char *sort_keys; 1719 int ret = 0; 1720 1721 ret = setup_sort_order(); 1722 if (ret) 1723 return ret; 1724 1725 sort_keys = sort_order; 1726 if (sort_keys == NULL) { 1727 if (is_strict_order(field_order)) { 1728 /* 1729 * If user specified field order but no sort order, 1730 * we'll honor it and not add default sort orders. 1731 */ 1732 return 0; 1733 } 1734 1735 sort_keys = get_default_sort_order(); 1736 } 1737 1738 str = strdup(sort_keys); 1739 if (str == NULL) { 1740 error("Not enough memory to setup sort keys"); 1741 return -ENOMEM; 1742 } 1743 1744 for (tok = strtok_r(str, ", ", &tmp); 1745 tok; tok = strtok_r(NULL, ", ", &tmp)) { 1746 ret = sort_dimension__add(tok); 1747 if (ret == -EINVAL) { 1748 error("Invalid --sort key: `%s'", tok); 1749 break; 1750 } else if (ret == -ESRCH) { 1751 error("Unknown --sort key: `%s'", tok); 1752 break; 1753 } 1754 } 1755 1756 free(str); 1757 return ret; 1758 } 1759 1760 void perf_hpp__set_elide(int idx, bool elide) 1761 { 1762 struct perf_hpp_fmt *fmt; 1763 struct hpp_sort_entry *hse; 1764 1765 perf_hpp__for_each_format(fmt) { 1766 if (!perf_hpp__is_sort_entry(fmt)) 1767 continue; 1768 1769 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1770 if (hse->se->se_width_idx == idx) { 1771 fmt->elide = elide; 1772 break; 1773 } 1774 } 1775 } 1776 1777 static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp) 1778 { 1779 if (list && strlist__nr_entries(list) == 1) { 1780 if (fp != NULL) 1781 fprintf(fp, "# %s: %s\n", list_name, 1782 strlist__entry(list, 0)->s); 1783 return true; 1784 } 1785 return false; 1786 } 1787 1788 static bool get_elide(int idx, FILE *output) 1789 { 1790 switch (idx) { 1791 case HISTC_SYMBOL: 1792 return __get_elide(symbol_conf.sym_list, "symbol", output); 1793 case HISTC_DSO: 1794 return __get_elide(symbol_conf.dso_list, "dso", output); 1795 case HISTC_COMM: 1796 return __get_elide(symbol_conf.comm_list, "comm", output); 1797 default: 1798 break; 1799 } 1800 1801 if (sort__mode != SORT_MODE__BRANCH) 1802 return false; 1803 1804 switch (idx) { 1805 case HISTC_SYMBOL_FROM: 1806 return __get_elide(symbol_conf.sym_from_list, "sym_from", output); 1807 case HISTC_SYMBOL_TO: 1808 return __get_elide(symbol_conf.sym_to_list, "sym_to", output); 1809 case HISTC_DSO_FROM: 1810 return __get_elide(symbol_conf.dso_from_list, "dso_from", output); 1811 case HISTC_DSO_TO: 1812 return __get_elide(symbol_conf.dso_to_list, "dso_to", output); 1813 default: 1814 break; 1815 } 1816 1817 return false; 1818 } 1819 1820 void sort__setup_elide(FILE *output) 1821 { 1822 struct perf_hpp_fmt *fmt; 1823 struct hpp_sort_entry *hse; 1824 1825 perf_hpp__for_each_format(fmt) { 1826 if (!perf_hpp__is_sort_entry(fmt)) 1827 continue; 1828 1829 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1830 fmt->elide = get_elide(hse->se->se_width_idx, output); 1831 } 1832 1833 /* 1834 * It makes no sense to elide all of sort entries. 1835 * Just revert them to show up again. 1836 */ 1837 perf_hpp__for_each_format(fmt) { 1838 if (!perf_hpp__is_sort_entry(fmt)) 1839 continue; 1840 1841 if (!fmt->elide) 1842 return; 1843 } 1844 1845 perf_hpp__for_each_format(fmt) { 1846 if (!perf_hpp__is_sort_entry(fmt)) 1847 continue; 1848 1849 fmt->elide = false; 1850 } 1851 } 1852 1853 static int output_field_add(char *tok) 1854 { 1855 unsigned int i; 1856 1857 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) { 1858 struct sort_dimension *sd = &common_sort_dimensions[i]; 1859 1860 if (strncasecmp(tok, sd->name, strlen(tok))) 1861 continue; 1862 1863 return __sort_dimension__add_output(sd); 1864 } 1865 1866 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { 1867 struct hpp_dimension *hd = &hpp_sort_dimensions[i]; 1868 1869 if (strncasecmp(tok, hd->name, strlen(tok))) 1870 continue; 1871 1872 return __hpp_dimension__add_output(hd); 1873 } 1874 1875 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 1876 struct sort_dimension *sd = &bstack_sort_dimensions[i]; 1877 1878 if (strncasecmp(tok, sd->name, strlen(tok))) 1879 continue; 1880 1881 return __sort_dimension__add_output(sd); 1882 } 1883 1884 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) { 1885 struct sort_dimension *sd = &memory_sort_dimensions[i]; 1886 1887 if (strncasecmp(tok, sd->name, strlen(tok))) 1888 continue; 1889 1890 return __sort_dimension__add_output(sd); 1891 } 1892 1893 return -ESRCH; 1894 } 1895 1896 static void reset_dimensions(void) 1897 { 1898 unsigned int i; 1899 1900 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) 1901 common_sort_dimensions[i].taken = 0; 1902 1903 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) 1904 hpp_sort_dimensions[i].taken = 0; 1905 1906 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) 1907 bstack_sort_dimensions[i].taken = 0; 1908 1909 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) 1910 memory_sort_dimensions[i].taken = 0; 1911 } 1912 1913 bool is_strict_order(const char *order) 1914 { 1915 return order && (*order != '+'); 1916 } 1917 1918 static int __setup_output_field(void) 1919 { 1920 char *tmp, *tok, *str, *strp; 1921 int ret = -EINVAL; 1922 1923 if (field_order == NULL) 1924 return 0; 1925 1926 strp = str = strdup(field_order); 1927 if (str == NULL) { 1928 error("Not enough memory to setup output fields"); 1929 return -ENOMEM; 1930 } 1931 1932 if (!is_strict_order(field_order)) 1933 strp++; 1934 1935 if (!strlen(strp)) { 1936 error("Invalid --fields key: `+'"); 1937 goto out; 1938 } 1939 1940 for (tok = strtok_r(strp, ", ", &tmp); 1941 tok; tok = strtok_r(NULL, ", ", &tmp)) { 1942 ret = output_field_add(tok); 1943 if (ret == -EINVAL) { 1944 error("Invalid --fields key: `%s'", tok); 1945 break; 1946 } else if (ret == -ESRCH) { 1947 error("Unknown --fields key: `%s'", tok); 1948 break; 1949 } 1950 } 1951 1952 out: 1953 free(str); 1954 return ret; 1955 } 1956 1957 int setup_sorting(void) 1958 { 1959 int err; 1960 1961 err = __setup_sorting(); 1962 if (err < 0) 1963 return err; 1964 1965 if (parent_pattern != default_parent_pattern) { 1966 err = sort_dimension__add("parent"); 1967 if (err < 0) 1968 return err; 1969 } 1970 1971 reset_dimensions(); 1972 1973 /* 1974 * perf diff doesn't use default hpp output fields. 1975 */ 1976 if (sort__mode != SORT_MODE__DIFF) 1977 perf_hpp__init(); 1978 1979 err = __setup_output_field(); 1980 if (err < 0) 1981 return err; 1982 1983 /* copy sort keys to output fields */ 1984 perf_hpp__setup_output_field(); 1985 /* and then copy output fields to sort keys */ 1986 perf_hpp__append_sort_keys(); 1987 1988 return 0; 1989 } 1990 1991 void reset_output_field(void) 1992 { 1993 sort__need_collapse = 0; 1994 sort__has_parent = 0; 1995 sort__has_sym = 0; 1996 sort__has_dso = 0; 1997 1998 field_order = NULL; 1999 sort_order = NULL; 2000 2001 reset_dimensions(); 2002 perf_hpp__reset_output_field(); 2003 } 2004