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 #include "evlist.h" 8 #include <traceevent/event-parse.h> 9 10 regex_t parent_regex; 11 const char default_parent_pattern[] = "^sys_|^do_page_fault"; 12 const char *parent_pattern = default_parent_pattern; 13 const char default_sort_order[] = "comm,dso,symbol"; 14 const char default_branch_sort_order[] = "comm,dso_from,symbol_from,symbol_to,cycles"; 15 const char default_mem_sort_order[] = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked"; 16 const char default_top_sort_order[] = "dso,symbol"; 17 const char default_diff_sort_order[] = "dso,symbol"; 18 const char default_tracepoint_sort_order[] = "trace"; 19 const char *sort_order; 20 const char *field_order; 21 regex_t ignore_callees_regex; 22 int have_ignore_callees = 0; 23 int sort__need_collapse = 0; 24 int sort__has_parent = 0; 25 int sort__has_sym = 0; 26 int sort__has_dso = 0; 27 int sort__has_socket = 0; 28 enum sort_mode sort__mode = SORT_MODE__NORMAL; 29 30 31 static int repsep_snprintf(char *bf, size_t size, const char *fmt, ...) 32 { 33 int n; 34 va_list ap; 35 36 va_start(ap, fmt); 37 n = vsnprintf(bf, size, fmt, ap); 38 if (symbol_conf.field_sep && n > 0) { 39 char *sep = bf; 40 41 while (1) { 42 sep = strchr(sep, *symbol_conf.field_sep); 43 if (sep == NULL) 44 break; 45 *sep = '.'; 46 } 47 } 48 va_end(ap); 49 50 if (n >= (int)size) 51 return size - 1; 52 return n; 53 } 54 55 static int64_t cmp_null(const void *l, const void *r) 56 { 57 if (!l && !r) 58 return 0; 59 else if (!l) 60 return -1; 61 else 62 return 1; 63 } 64 65 /* --sort pid */ 66 67 static int64_t 68 sort__thread_cmp(struct hist_entry *left, struct hist_entry *right) 69 { 70 return right->thread->tid - left->thread->tid; 71 } 72 73 static int hist_entry__thread_snprintf(struct hist_entry *he, char *bf, 74 size_t size, unsigned int width) 75 { 76 const char *comm = thread__comm_str(he->thread); 77 78 width = max(7U, width) - 6; 79 return repsep_snprintf(bf, size, "%5d:%-*.*s", he->thread->tid, 80 width, width, comm ?: ""); 81 } 82 83 struct sort_entry sort_thread = { 84 .se_header = " Pid:Command", 85 .se_cmp = sort__thread_cmp, 86 .se_snprintf = hist_entry__thread_snprintf, 87 .se_width_idx = HISTC_THREAD, 88 }; 89 90 /* --sort comm */ 91 92 static int64_t 93 sort__comm_cmp(struct hist_entry *left, struct hist_entry *right) 94 { 95 /* Compare the addr that should be unique among comm */ 96 return strcmp(comm__str(right->comm), comm__str(left->comm)); 97 } 98 99 static int64_t 100 sort__comm_collapse(struct hist_entry *left, struct hist_entry *right) 101 { 102 /* Compare the addr that should be unique among comm */ 103 return strcmp(comm__str(right->comm), comm__str(left->comm)); 104 } 105 106 static int64_t 107 sort__comm_sort(struct hist_entry *left, struct hist_entry *right) 108 { 109 return strcmp(comm__str(right->comm), comm__str(left->comm)); 110 } 111 112 static int hist_entry__comm_snprintf(struct hist_entry *he, char *bf, 113 size_t size, unsigned int width) 114 { 115 return repsep_snprintf(bf, size, "%-*.*s", width, width, comm__str(he->comm)); 116 } 117 118 struct sort_entry sort_comm = { 119 .se_header = "Command", 120 .se_cmp = sort__comm_cmp, 121 .se_collapse = sort__comm_collapse, 122 .se_sort = sort__comm_sort, 123 .se_snprintf = hist_entry__comm_snprintf, 124 .se_width_idx = HISTC_COMM, 125 }; 126 127 /* --sort dso */ 128 129 static int64_t _sort__dso_cmp(struct map *map_l, struct map *map_r) 130 { 131 struct dso *dso_l = map_l ? map_l->dso : NULL; 132 struct dso *dso_r = map_r ? map_r->dso : NULL; 133 const char *dso_name_l, *dso_name_r; 134 135 if (!dso_l || !dso_r) 136 return cmp_null(dso_r, dso_l); 137 138 if (verbose) { 139 dso_name_l = dso_l->long_name; 140 dso_name_r = dso_r->long_name; 141 } else { 142 dso_name_l = dso_l->short_name; 143 dso_name_r = dso_r->short_name; 144 } 145 146 return strcmp(dso_name_l, dso_name_r); 147 } 148 149 static int64_t 150 sort__dso_cmp(struct hist_entry *left, struct hist_entry *right) 151 { 152 return _sort__dso_cmp(right->ms.map, left->ms.map); 153 } 154 155 static int _hist_entry__dso_snprintf(struct map *map, char *bf, 156 size_t size, unsigned int width) 157 { 158 if (map && map->dso) { 159 const char *dso_name = !verbose ? map->dso->short_name : 160 map->dso->long_name; 161 return repsep_snprintf(bf, size, "%-*.*s", width, width, dso_name); 162 } 163 164 return repsep_snprintf(bf, size, "%-*.*s", width, width, "[unknown]"); 165 } 166 167 static int hist_entry__dso_snprintf(struct hist_entry *he, char *bf, 168 size_t size, unsigned int width) 169 { 170 return _hist_entry__dso_snprintf(he->ms.map, bf, size, width); 171 } 172 173 struct sort_entry sort_dso = { 174 .se_header = "Shared Object", 175 .se_cmp = sort__dso_cmp, 176 .se_snprintf = hist_entry__dso_snprintf, 177 .se_width_idx = HISTC_DSO, 178 }; 179 180 /* --sort symbol */ 181 182 static int64_t _sort__addr_cmp(u64 left_ip, u64 right_ip) 183 { 184 return (int64_t)(right_ip - left_ip); 185 } 186 187 static int64_t _sort__sym_cmp(struct symbol *sym_l, struct symbol *sym_r) 188 { 189 if (!sym_l || !sym_r) 190 return cmp_null(sym_l, sym_r); 191 192 if (sym_l == sym_r) 193 return 0; 194 195 if (sym_l->start != sym_r->start) 196 return (int64_t)(sym_r->start - sym_l->start); 197 198 return (int64_t)(sym_r->end - sym_l->end); 199 } 200 201 static int64_t 202 sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) 203 { 204 int64_t ret; 205 206 if (!left->ms.sym && !right->ms.sym) 207 return _sort__addr_cmp(left->ip, right->ip); 208 209 /* 210 * comparing symbol address alone is not enough since it's a 211 * relative address within a dso. 212 */ 213 if (!sort__has_dso) { 214 ret = sort__dso_cmp(left, right); 215 if (ret != 0) 216 return ret; 217 } 218 219 return _sort__sym_cmp(left->ms.sym, right->ms.sym); 220 } 221 222 static int64_t 223 sort__sym_sort(struct hist_entry *left, struct hist_entry *right) 224 { 225 if (!left->ms.sym || !right->ms.sym) 226 return cmp_null(left->ms.sym, right->ms.sym); 227 228 return strcmp(right->ms.sym->name, left->ms.sym->name); 229 } 230 231 static int _hist_entry__sym_snprintf(struct map *map, struct symbol *sym, 232 u64 ip, char level, char *bf, size_t size, 233 unsigned int width) 234 { 235 size_t ret = 0; 236 237 if (verbose) { 238 char o = map ? dso__symtab_origin(map->dso) : '!'; 239 ret += repsep_snprintf(bf, size, "%-#*llx %c ", 240 BITS_PER_LONG / 4 + 2, ip, o); 241 } 242 243 ret += repsep_snprintf(bf + ret, size - ret, "[%c] ", level); 244 if (sym && map) { 245 if (map->type == MAP__VARIABLE) { 246 ret += repsep_snprintf(bf + ret, size - ret, "%s", sym->name); 247 ret += repsep_snprintf(bf + ret, size - ret, "+0x%llx", 248 ip - map->unmap_ip(map, sym->start)); 249 ret += repsep_snprintf(bf + ret, size - ret, "%-*s", 250 width - ret, ""); 251 } else { 252 ret += repsep_snprintf(bf + ret, size - ret, "%-*s", 253 width - ret, 254 sym->name); 255 } 256 } else { 257 size_t len = BITS_PER_LONG / 4; 258 ret += repsep_snprintf(bf + ret, size - ret, "%-#.*llx", 259 len, ip); 260 ret += repsep_snprintf(bf + ret, size - ret, "%-*s", 261 width - ret, ""); 262 } 263 264 if (ret > width) 265 bf[width] = '\0'; 266 267 return width; 268 } 269 270 static int hist_entry__sym_snprintf(struct hist_entry *he, char *bf, 271 size_t size, unsigned int width) 272 { 273 return _hist_entry__sym_snprintf(he->ms.map, he->ms.sym, he->ip, 274 he->level, bf, size, width); 275 } 276 277 struct sort_entry sort_sym = { 278 .se_header = "Symbol", 279 .se_cmp = sort__sym_cmp, 280 .se_sort = sort__sym_sort, 281 .se_snprintf = hist_entry__sym_snprintf, 282 .se_width_idx = HISTC_SYMBOL, 283 }; 284 285 /* --sort srcline */ 286 287 static int64_t 288 sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right) 289 { 290 if (!left->srcline) { 291 if (!left->ms.map) 292 left->srcline = SRCLINE_UNKNOWN; 293 else { 294 struct map *map = left->ms.map; 295 left->srcline = get_srcline(map->dso, 296 map__rip_2objdump(map, left->ip), 297 left->ms.sym, true); 298 } 299 } 300 if (!right->srcline) { 301 if (!right->ms.map) 302 right->srcline = SRCLINE_UNKNOWN; 303 else { 304 struct map *map = right->ms.map; 305 right->srcline = get_srcline(map->dso, 306 map__rip_2objdump(map, right->ip), 307 right->ms.sym, true); 308 } 309 } 310 return strcmp(right->srcline, left->srcline); 311 } 312 313 static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf, 314 size_t size, unsigned int width) 315 { 316 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcline); 317 } 318 319 struct sort_entry sort_srcline = { 320 .se_header = "Source:Line", 321 .se_cmp = sort__srcline_cmp, 322 .se_snprintf = hist_entry__srcline_snprintf, 323 .se_width_idx = HISTC_SRCLINE, 324 }; 325 326 /* --sort srcfile */ 327 328 static char no_srcfile[1]; 329 330 static char *get_srcfile(struct hist_entry *e) 331 { 332 char *sf, *p; 333 struct map *map = e->ms.map; 334 335 sf = __get_srcline(map->dso, map__rip_2objdump(map, e->ip), 336 e->ms.sym, false, true); 337 if (!strcmp(sf, SRCLINE_UNKNOWN)) 338 return no_srcfile; 339 p = strchr(sf, ':'); 340 if (p && *sf) { 341 *p = 0; 342 return sf; 343 } 344 free(sf); 345 return no_srcfile; 346 } 347 348 static int64_t 349 sort__srcfile_cmp(struct hist_entry *left, struct hist_entry *right) 350 { 351 if (!left->srcfile) { 352 if (!left->ms.map) 353 left->srcfile = no_srcfile; 354 else 355 left->srcfile = get_srcfile(left); 356 } 357 if (!right->srcfile) { 358 if (!right->ms.map) 359 right->srcfile = no_srcfile; 360 else 361 right->srcfile = get_srcfile(right); 362 } 363 return strcmp(right->srcfile, left->srcfile); 364 } 365 366 static int hist_entry__srcfile_snprintf(struct hist_entry *he, char *bf, 367 size_t size, unsigned int width) 368 { 369 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcfile); 370 } 371 372 struct sort_entry sort_srcfile = { 373 .se_header = "Source File", 374 .se_cmp = sort__srcfile_cmp, 375 .se_snprintf = hist_entry__srcfile_snprintf, 376 .se_width_idx = HISTC_SRCFILE, 377 }; 378 379 /* --sort parent */ 380 381 static int64_t 382 sort__parent_cmp(struct hist_entry *left, struct hist_entry *right) 383 { 384 struct symbol *sym_l = left->parent; 385 struct symbol *sym_r = right->parent; 386 387 if (!sym_l || !sym_r) 388 return cmp_null(sym_l, sym_r); 389 390 return strcmp(sym_r->name, sym_l->name); 391 } 392 393 static int hist_entry__parent_snprintf(struct hist_entry *he, char *bf, 394 size_t size, unsigned int width) 395 { 396 return repsep_snprintf(bf, size, "%-*.*s", width, width, 397 he->parent ? he->parent->name : "[other]"); 398 } 399 400 struct sort_entry sort_parent = { 401 .se_header = "Parent symbol", 402 .se_cmp = sort__parent_cmp, 403 .se_snprintf = hist_entry__parent_snprintf, 404 .se_width_idx = HISTC_PARENT, 405 }; 406 407 /* --sort cpu */ 408 409 static int64_t 410 sort__cpu_cmp(struct hist_entry *left, struct hist_entry *right) 411 { 412 return right->cpu - left->cpu; 413 } 414 415 static int hist_entry__cpu_snprintf(struct hist_entry *he, char *bf, 416 size_t size, unsigned int width) 417 { 418 return repsep_snprintf(bf, size, "%*.*d", width, width, he->cpu); 419 } 420 421 struct sort_entry sort_cpu = { 422 .se_header = "CPU", 423 .se_cmp = sort__cpu_cmp, 424 .se_snprintf = hist_entry__cpu_snprintf, 425 .se_width_idx = HISTC_CPU, 426 }; 427 428 /* --sort socket */ 429 430 static int64_t 431 sort__socket_cmp(struct hist_entry *left, struct hist_entry *right) 432 { 433 return right->socket - left->socket; 434 } 435 436 static int hist_entry__socket_snprintf(struct hist_entry *he, char *bf, 437 size_t size, unsigned int width) 438 { 439 return repsep_snprintf(bf, size, "%*.*d", width, width-3, he->socket); 440 } 441 442 struct sort_entry sort_socket = { 443 .se_header = "Socket", 444 .se_cmp = sort__socket_cmp, 445 .se_snprintf = hist_entry__socket_snprintf, 446 .se_width_idx = HISTC_SOCKET, 447 }; 448 449 /* --sort trace */ 450 451 static char *get_trace_output(struct hist_entry *he) 452 { 453 struct trace_seq seq; 454 struct perf_evsel *evsel; 455 struct pevent_record rec = { 456 .data = he->raw_data, 457 .size = he->raw_size, 458 }; 459 460 evsel = hists_to_evsel(he->hists); 461 462 trace_seq_init(&seq); 463 if (symbol_conf.raw_trace) { 464 pevent_print_fields(&seq, he->raw_data, he->raw_size, 465 evsel->tp_format); 466 } else { 467 pevent_event_info(&seq, evsel->tp_format, &rec); 468 } 469 return seq.buffer; 470 } 471 472 static int64_t 473 sort__trace_cmp(struct hist_entry *left, struct hist_entry *right) 474 { 475 struct perf_evsel *evsel; 476 477 evsel = hists_to_evsel(left->hists); 478 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) 479 return 0; 480 481 if (left->trace_output == NULL) 482 left->trace_output = get_trace_output(left); 483 if (right->trace_output == NULL) 484 right->trace_output = get_trace_output(right); 485 486 hists__new_col_len(left->hists, HISTC_TRACE, strlen(left->trace_output)); 487 hists__new_col_len(right->hists, HISTC_TRACE, strlen(right->trace_output)); 488 489 return strcmp(right->trace_output, left->trace_output); 490 } 491 492 static int hist_entry__trace_snprintf(struct hist_entry *he, char *bf, 493 size_t size, unsigned int width) 494 { 495 struct perf_evsel *evsel; 496 497 evsel = hists_to_evsel(he->hists); 498 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) 499 return scnprintf(bf, size, "%-*.*s", width, width, "N/A"); 500 501 if (he->trace_output == NULL) 502 he->trace_output = get_trace_output(he); 503 return repsep_snprintf(bf, size, "%-*.*s", width, width, he->trace_output); 504 } 505 506 struct sort_entry sort_trace = { 507 .se_header = "Trace output", 508 .se_cmp = sort__trace_cmp, 509 .se_snprintf = hist_entry__trace_snprintf, 510 .se_width_idx = HISTC_TRACE, 511 }; 512 513 /* sort keys for branch stacks */ 514 515 static int64_t 516 sort__dso_from_cmp(struct hist_entry *left, struct hist_entry *right) 517 { 518 if (!left->branch_info || !right->branch_info) 519 return cmp_null(left->branch_info, right->branch_info); 520 521 return _sort__dso_cmp(left->branch_info->from.map, 522 right->branch_info->from.map); 523 } 524 525 static int hist_entry__dso_from_snprintf(struct hist_entry *he, char *bf, 526 size_t size, unsigned int width) 527 { 528 if (he->branch_info) 529 return _hist_entry__dso_snprintf(he->branch_info->from.map, 530 bf, size, width); 531 else 532 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 533 } 534 535 static int64_t 536 sort__dso_to_cmp(struct hist_entry *left, struct hist_entry *right) 537 { 538 if (!left->branch_info || !right->branch_info) 539 return cmp_null(left->branch_info, right->branch_info); 540 541 return _sort__dso_cmp(left->branch_info->to.map, 542 right->branch_info->to.map); 543 } 544 545 static int hist_entry__dso_to_snprintf(struct hist_entry *he, char *bf, 546 size_t size, unsigned int width) 547 { 548 if (he->branch_info) 549 return _hist_entry__dso_snprintf(he->branch_info->to.map, 550 bf, size, width); 551 else 552 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 553 } 554 555 static int64_t 556 sort__sym_from_cmp(struct hist_entry *left, struct hist_entry *right) 557 { 558 struct addr_map_symbol *from_l = &left->branch_info->from; 559 struct addr_map_symbol *from_r = &right->branch_info->from; 560 561 if (!left->branch_info || !right->branch_info) 562 return cmp_null(left->branch_info, right->branch_info); 563 564 from_l = &left->branch_info->from; 565 from_r = &right->branch_info->from; 566 567 if (!from_l->sym && !from_r->sym) 568 return _sort__addr_cmp(from_l->addr, from_r->addr); 569 570 return _sort__sym_cmp(from_l->sym, from_r->sym); 571 } 572 573 static int64_t 574 sort__sym_to_cmp(struct hist_entry *left, struct hist_entry *right) 575 { 576 struct addr_map_symbol *to_l, *to_r; 577 578 if (!left->branch_info || !right->branch_info) 579 return cmp_null(left->branch_info, right->branch_info); 580 581 to_l = &left->branch_info->to; 582 to_r = &right->branch_info->to; 583 584 if (!to_l->sym && !to_r->sym) 585 return _sort__addr_cmp(to_l->addr, to_r->addr); 586 587 return _sort__sym_cmp(to_l->sym, to_r->sym); 588 } 589 590 static int hist_entry__sym_from_snprintf(struct hist_entry *he, char *bf, 591 size_t size, unsigned int width) 592 { 593 if (he->branch_info) { 594 struct addr_map_symbol *from = &he->branch_info->from; 595 596 return _hist_entry__sym_snprintf(from->map, from->sym, from->addr, 597 he->level, bf, size, width); 598 } 599 600 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 601 } 602 603 static int hist_entry__sym_to_snprintf(struct hist_entry *he, char *bf, 604 size_t size, unsigned int width) 605 { 606 if (he->branch_info) { 607 struct addr_map_symbol *to = &he->branch_info->to; 608 609 return _hist_entry__sym_snprintf(to->map, to->sym, to->addr, 610 he->level, bf, size, width); 611 } 612 613 return repsep_snprintf(bf, size, "%-*.*s", width, width, "N/A"); 614 } 615 616 struct sort_entry sort_dso_from = { 617 .se_header = "Source Shared Object", 618 .se_cmp = sort__dso_from_cmp, 619 .se_snprintf = hist_entry__dso_from_snprintf, 620 .se_width_idx = HISTC_DSO_FROM, 621 }; 622 623 struct sort_entry sort_dso_to = { 624 .se_header = "Target Shared Object", 625 .se_cmp = sort__dso_to_cmp, 626 .se_snprintf = hist_entry__dso_to_snprintf, 627 .se_width_idx = HISTC_DSO_TO, 628 }; 629 630 struct sort_entry sort_sym_from = { 631 .se_header = "Source Symbol", 632 .se_cmp = sort__sym_from_cmp, 633 .se_snprintf = hist_entry__sym_from_snprintf, 634 .se_width_idx = HISTC_SYMBOL_FROM, 635 }; 636 637 struct sort_entry sort_sym_to = { 638 .se_header = "Target Symbol", 639 .se_cmp = sort__sym_to_cmp, 640 .se_snprintf = hist_entry__sym_to_snprintf, 641 .se_width_idx = HISTC_SYMBOL_TO, 642 }; 643 644 static int64_t 645 sort__mispredict_cmp(struct hist_entry *left, struct hist_entry *right) 646 { 647 unsigned char mp, p; 648 649 if (!left->branch_info || !right->branch_info) 650 return cmp_null(left->branch_info, right->branch_info); 651 652 mp = left->branch_info->flags.mispred != right->branch_info->flags.mispred; 653 p = left->branch_info->flags.predicted != right->branch_info->flags.predicted; 654 return mp || p; 655 } 656 657 static int hist_entry__mispredict_snprintf(struct hist_entry *he, char *bf, 658 size_t size, unsigned int width){ 659 static const char *out = "N/A"; 660 661 if (he->branch_info) { 662 if (he->branch_info->flags.predicted) 663 out = "N"; 664 else if (he->branch_info->flags.mispred) 665 out = "Y"; 666 } 667 668 return repsep_snprintf(bf, size, "%-*.*s", width, width, out); 669 } 670 671 static int64_t 672 sort__cycles_cmp(struct hist_entry *left, struct hist_entry *right) 673 { 674 return left->branch_info->flags.cycles - 675 right->branch_info->flags.cycles; 676 } 677 678 static int hist_entry__cycles_snprintf(struct hist_entry *he, char *bf, 679 size_t size, unsigned int width) 680 { 681 if (he->branch_info->flags.cycles == 0) 682 return repsep_snprintf(bf, size, "%-*s", width, "-"); 683 return repsep_snprintf(bf, size, "%-*hd", width, 684 he->branch_info->flags.cycles); 685 } 686 687 struct sort_entry sort_cycles = { 688 .se_header = "Basic Block Cycles", 689 .se_cmp = sort__cycles_cmp, 690 .se_snprintf = hist_entry__cycles_snprintf, 691 .se_width_idx = HISTC_CYCLES, 692 }; 693 694 /* --sort daddr_sym */ 695 static int64_t 696 sort__daddr_cmp(struct hist_entry *left, struct hist_entry *right) 697 { 698 uint64_t l = 0, r = 0; 699 700 if (left->mem_info) 701 l = left->mem_info->daddr.addr; 702 if (right->mem_info) 703 r = right->mem_info->daddr.addr; 704 705 return (int64_t)(r - l); 706 } 707 708 static int hist_entry__daddr_snprintf(struct hist_entry *he, char *bf, 709 size_t size, unsigned int width) 710 { 711 uint64_t addr = 0; 712 struct map *map = NULL; 713 struct symbol *sym = NULL; 714 715 if (he->mem_info) { 716 addr = he->mem_info->daddr.addr; 717 map = he->mem_info->daddr.map; 718 sym = he->mem_info->daddr.sym; 719 } 720 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size, 721 width); 722 } 723 724 static int64_t 725 sort__iaddr_cmp(struct hist_entry *left, struct hist_entry *right) 726 { 727 uint64_t l = 0, r = 0; 728 729 if (left->mem_info) 730 l = left->mem_info->iaddr.addr; 731 if (right->mem_info) 732 r = right->mem_info->iaddr.addr; 733 734 return (int64_t)(r - l); 735 } 736 737 static int hist_entry__iaddr_snprintf(struct hist_entry *he, char *bf, 738 size_t size, unsigned int width) 739 { 740 uint64_t addr = 0; 741 struct map *map = NULL; 742 struct symbol *sym = NULL; 743 744 if (he->mem_info) { 745 addr = he->mem_info->iaddr.addr; 746 map = he->mem_info->iaddr.map; 747 sym = he->mem_info->iaddr.sym; 748 } 749 return _hist_entry__sym_snprintf(map, sym, addr, he->level, bf, size, 750 width); 751 } 752 753 static int64_t 754 sort__dso_daddr_cmp(struct hist_entry *left, struct hist_entry *right) 755 { 756 struct map *map_l = NULL; 757 struct map *map_r = NULL; 758 759 if (left->mem_info) 760 map_l = left->mem_info->daddr.map; 761 if (right->mem_info) 762 map_r = right->mem_info->daddr.map; 763 764 return _sort__dso_cmp(map_l, map_r); 765 } 766 767 static int hist_entry__dso_daddr_snprintf(struct hist_entry *he, char *bf, 768 size_t size, unsigned int width) 769 { 770 struct map *map = NULL; 771 772 if (he->mem_info) 773 map = he->mem_info->daddr.map; 774 775 return _hist_entry__dso_snprintf(map, bf, size, width); 776 } 777 778 static int64_t 779 sort__locked_cmp(struct hist_entry *left, struct hist_entry *right) 780 { 781 union perf_mem_data_src data_src_l; 782 union perf_mem_data_src data_src_r; 783 784 if (left->mem_info) 785 data_src_l = left->mem_info->data_src; 786 else 787 data_src_l.mem_lock = PERF_MEM_LOCK_NA; 788 789 if (right->mem_info) 790 data_src_r = right->mem_info->data_src; 791 else 792 data_src_r.mem_lock = PERF_MEM_LOCK_NA; 793 794 return (int64_t)(data_src_r.mem_lock - data_src_l.mem_lock); 795 } 796 797 static int hist_entry__locked_snprintf(struct hist_entry *he, char *bf, 798 size_t size, unsigned int width) 799 { 800 const char *out; 801 u64 mask = PERF_MEM_LOCK_NA; 802 803 if (he->mem_info) 804 mask = he->mem_info->data_src.mem_lock; 805 806 if (mask & PERF_MEM_LOCK_NA) 807 out = "N/A"; 808 else if (mask & PERF_MEM_LOCK_LOCKED) 809 out = "Yes"; 810 else 811 out = "No"; 812 813 return repsep_snprintf(bf, size, "%-*s", width, out); 814 } 815 816 static int64_t 817 sort__tlb_cmp(struct hist_entry *left, struct hist_entry *right) 818 { 819 union perf_mem_data_src data_src_l; 820 union perf_mem_data_src data_src_r; 821 822 if (left->mem_info) 823 data_src_l = left->mem_info->data_src; 824 else 825 data_src_l.mem_dtlb = PERF_MEM_TLB_NA; 826 827 if (right->mem_info) 828 data_src_r = right->mem_info->data_src; 829 else 830 data_src_r.mem_dtlb = PERF_MEM_TLB_NA; 831 832 return (int64_t)(data_src_r.mem_dtlb - data_src_l.mem_dtlb); 833 } 834 835 static const char * const tlb_access[] = { 836 "N/A", 837 "HIT", 838 "MISS", 839 "L1", 840 "L2", 841 "Walker", 842 "Fault", 843 }; 844 #define NUM_TLB_ACCESS (sizeof(tlb_access)/sizeof(const char *)) 845 846 static int hist_entry__tlb_snprintf(struct hist_entry *he, char *bf, 847 size_t size, unsigned int width) 848 { 849 char out[64]; 850 size_t sz = sizeof(out) - 1; /* -1 for null termination */ 851 size_t l = 0, i; 852 u64 m = PERF_MEM_TLB_NA; 853 u64 hit, miss; 854 855 out[0] = '\0'; 856 857 if (he->mem_info) 858 m = he->mem_info->data_src.mem_dtlb; 859 860 hit = m & PERF_MEM_TLB_HIT; 861 miss = m & PERF_MEM_TLB_MISS; 862 863 /* already taken care of */ 864 m &= ~(PERF_MEM_TLB_HIT|PERF_MEM_TLB_MISS); 865 866 for (i = 0; m && i < NUM_TLB_ACCESS; i++, m >>= 1) { 867 if (!(m & 0x1)) 868 continue; 869 if (l) { 870 strcat(out, " or "); 871 l += 4; 872 } 873 strncat(out, tlb_access[i], sz - l); 874 l += strlen(tlb_access[i]); 875 } 876 if (*out == '\0') 877 strcpy(out, "N/A"); 878 if (hit) 879 strncat(out, " hit", sz - l); 880 if (miss) 881 strncat(out, " miss", sz - l); 882 883 return repsep_snprintf(bf, size, "%-*s", width, out); 884 } 885 886 static int64_t 887 sort__lvl_cmp(struct hist_entry *left, struct hist_entry *right) 888 { 889 union perf_mem_data_src data_src_l; 890 union perf_mem_data_src data_src_r; 891 892 if (left->mem_info) 893 data_src_l = left->mem_info->data_src; 894 else 895 data_src_l.mem_lvl = PERF_MEM_LVL_NA; 896 897 if (right->mem_info) 898 data_src_r = right->mem_info->data_src; 899 else 900 data_src_r.mem_lvl = PERF_MEM_LVL_NA; 901 902 return (int64_t)(data_src_r.mem_lvl - data_src_l.mem_lvl); 903 } 904 905 static const char * const mem_lvl[] = { 906 "N/A", 907 "HIT", 908 "MISS", 909 "L1", 910 "LFB", 911 "L2", 912 "L3", 913 "Local RAM", 914 "Remote RAM (1 hop)", 915 "Remote RAM (2 hops)", 916 "Remote Cache (1 hop)", 917 "Remote Cache (2 hops)", 918 "I/O", 919 "Uncached", 920 }; 921 #define NUM_MEM_LVL (sizeof(mem_lvl)/sizeof(const char *)) 922 923 static int hist_entry__lvl_snprintf(struct hist_entry *he, char *bf, 924 size_t size, unsigned int width) 925 { 926 char out[64]; 927 size_t sz = sizeof(out) - 1; /* -1 for null termination */ 928 size_t i, l = 0; 929 u64 m = PERF_MEM_LVL_NA; 930 u64 hit, miss; 931 932 if (he->mem_info) 933 m = he->mem_info->data_src.mem_lvl; 934 935 out[0] = '\0'; 936 937 hit = m & PERF_MEM_LVL_HIT; 938 miss = m & PERF_MEM_LVL_MISS; 939 940 /* already taken care of */ 941 m &= ~(PERF_MEM_LVL_HIT|PERF_MEM_LVL_MISS); 942 943 for (i = 0; m && i < NUM_MEM_LVL; i++, m >>= 1) { 944 if (!(m & 0x1)) 945 continue; 946 if (l) { 947 strcat(out, " or "); 948 l += 4; 949 } 950 strncat(out, mem_lvl[i], sz - l); 951 l += strlen(mem_lvl[i]); 952 } 953 if (*out == '\0') 954 strcpy(out, "N/A"); 955 if (hit) 956 strncat(out, " hit", sz - l); 957 if (miss) 958 strncat(out, " miss", sz - l); 959 960 return repsep_snprintf(bf, size, "%-*s", width, out); 961 } 962 963 static int64_t 964 sort__snoop_cmp(struct hist_entry *left, struct hist_entry *right) 965 { 966 union perf_mem_data_src data_src_l; 967 union perf_mem_data_src data_src_r; 968 969 if (left->mem_info) 970 data_src_l = left->mem_info->data_src; 971 else 972 data_src_l.mem_snoop = PERF_MEM_SNOOP_NA; 973 974 if (right->mem_info) 975 data_src_r = right->mem_info->data_src; 976 else 977 data_src_r.mem_snoop = PERF_MEM_SNOOP_NA; 978 979 return (int64_t)(data_src_r.mem_snoop - data_src_l.mem_snoop); 980 } 981 982 static const char * const snoop_access[] = { 983 "N/A", 984 "None", 985 "Miss", 986 "Hit", 987 "HitM", 988 }; 989 #define NUM_SNOOP_ACCESS (sizeof(snoop_access)/sizeof(const char *)) 990 991 static int hist_entry__snoop_snprintf(struct hist_entry *he, char *bf, 992 size_t size, unsigned int width) 993 { 994 char out[64]; 995 size_t sz = sizeof(out) - 1; /* -1 for null termination */ 996 size_t i, l = 0; 997 u64 m = PERF_MEM_SNOOP_NA; 998 999 out[0] = '\0'; 1000 1001 if (he->mem_info) 1002 m = he->mem_info->data_src.mem_snoop; 1003 1004 for (i = 0; m && i < NUM_SNOOP_ACCESS; i++, m >>= 1) { 1005 if (!(m & 0x1)) 1006 continue; 1007 if (l) { 1008 strcat(out, " or "); 1009 l += 4; 1010 } 1011 strncat(out, snoop_access[i], sz - l); 1012 l += strlen(snoop_access[i]); 1013 } 1014 1015 if (*out == '\0') 1016 strcpy(out, "N/A"); 1017 1018 return repsep_snprintf(bf, size, "%-*s", width, out); 1019 } 1020 1021 static inline u64 cl_address(u64 address) 1022 { 1023 /* return the cacheline of the address */ 1024 return (address & ~(cacheline_size - 1)); 1025 } 1026 1027 static int64_t 1028 sort__dcacheline_cmp(struct hist_entry *left, struct hist_entry *right) 1029 { 1030 u64 l, r; 1031 struct map *l_map, *r_map; 1032 1033 if (!left->mem_info) return -1; 1034 if (!right->mem_info) return 1; 1035 1036 /* group event types together */ 1037 if (left->cpumode > right->cpumode) return -1; 1038 if (left->cpumode < right->cpumode) return 1; 1039 1040 l_map = left->mem_info->daddr.map; 1041 r_map = right->mem_info->daddr.map; 1042 1043 /* if both are NULL, jump to sort on al_addr instead */ 1044 if (!l_map && !r_map) 1045 goto addr; 1046 1047 if (!l_map) return -1; 1048 if (!r_map) return 1; 1049 1050 if (l_map->maj > r_map->maj) return -1; 1051 if (l_map->maj < r_map->maj) return 1; 1052 1053 if (l_map->min > r_map->min) return -1; 1054 if (l_map->min < r_map->min) return 1; 1055 1056 if (l_map->ino > r_map->ino) return -1; 1057 if (l_map->ino < r_map->ino) return 1; 1058 1059 if (l_map->ino_generation > r_map->ino_generation) return -1; 1060 if (l_map->ino_generation < r_map->ino_generation) return 1; 1061 1062 /* 1063 * Addresses with no major/minor numbers are assumed to be 1064 * anonymous in userspace. Sort those on pid then address. 1065 * 1066 * The kernel and non-zero major/minor mapped areas are 1067 * assumed to be unity mapped. Sort those on address. 1068 */ 1069 1070 if ((left->cpumode != PERF_RECORD_MISC_KERNEL) && 1071 (!(l_map->flags & MAP_SHARED)) && 1072 !l_map->maj && !l_map->min && !l_map->ino && 1073 !l_map->ino_generation) { 1074 /* userspace anonymous */ 1075 1076 if (left->thread->pid_ > right->thread->pid_) return -1; 1077 if (left->thread->pid_ < right->thread->pid_) return 1; 1078 } 1079 1080 addr: 1081 /* al_addr does all the right addr - start + offset calculations */ 1082 l = cl_address(left->mem_info->daddr.al_addr); 1083 r = cl_address(right->mem_info->daddr.al_addr); 1084 1085 if (l > r) return -1; 1086 if (l < r) return 1; 1087 1088 return 0; 1089 } 1090 1091 static int hist_entry__dcacheline_snprintf(struct hist_entry *he, char *bf, 1092 size_t size, unsigned int width) 1093 { 1094 1095 uint64_t addr = 0; 1096 struct map *map = NULL; 1097 struct symbol *sym = NULL; 1098 char level = he->level; 1099 1100 if (he->mem_info) { 1101 addr = cl_address(he->mem_info->daddr.al_addr); 1102 map = he->mem_info->daddr.map; 1103 sym = he->mem_info->daddr.sym; 1104 1105 /* print [s] for shared data mmaps */ 1106 if ((he->cpumode != PERF_RECORD_MISC_KERNEL) && 1107 map && (map->type == MAP__VARIABLE) && 1108 (map->flags & MAP_SHARED) && 1109 (map->maj || map->min || map->ino || 1110 map->ino_generation)) 1111 level = 's'; 1112 else if (!map) 1113 level = 'X'; 1114 } 1115 return _hist_entry__sym_snprintf(map, sym, addr, level, bf, size, 1116 width); 1117 } 1118 1119 struct sort_entry sort_mispredict = { 1120 .se_header = "Branch Mispredicted", 1121 .se_cmp = sort__mispredict_cmp, 1122 .se_snprintf = hist_entry__mispredict_snprintf, 1123 .se_width_idx = HISTC_MISPREDICT, 1124 }; 1125 1126 static u64 he_weight(struct hist_entry *he) 1127 { 1128 return he->stat.nr_events ? he->stat.weight / he->stat.nr_events : 0; 1129 } 1130 1131 static int64_t 1132 sort__local_weight_cmp(struct hist_entry *left, struct hist_entry *right) 1133 { 1134 return he_weight(left) - he_weight(right); 1135 } 1136 1137 static int hist_entry__local_weight_snprintf(struct hist_entry *he, char *bf, 1138 size_t size, unsigned int width) 1139 { 1140 return repsep_snprintf(bf, size, "%-*llu", width, he_weight(he)); 1141 } 1142 1143 struct sort_entry sort_local_weight = { 1144 .se_header = "Local Weight", 1145 .se_cmp = sort__local_weight_cmp, 1146 .se_snprintf = hist_entry__local_weight_snprintf, 1147 .se_width_idx = HISTC_LOCAL_WEIGHT, 1148 }; 1149 1150 static int64_t 1151 sort__global_weight_cmp(struct hist_entry *left, struct hist_entry *right) 1152 { 1153 return left->stat.weight - right->stat.weight; 1154 } 1155 1156 static int hist_entry__global_weight_snprintf(struct hist_entry *he, char *bf, 1157 size_t size, unsigned int width) 1158 { 1159 return repsep_snprintf(bf, size, "%-*llu", width, he->stat.weight); 1160 } 1161 1162 struct sort_entry sort_global_weight = { 1163 .se_header = "Weight", 1164 .se_cmp = sort__global_weight_cmp, 1165 .se_snprintf = hist_entry__global_weight_snprintf, 1166 .se_width_idx = HISTC_GLOBAL_WEIGHT, 1167 }; 1168 1169 struct sort_entry sort_mem_daddr_sym = { 1170 .se_header = "Data Symbol", 1171 .se_cmp = sort__daddr_cmp, 1172 .se_snprintf = hist_entry__daddr_snprintf, 1173 .se_width_idx = HISTC_MEM_DADDR_SYMBOL, 1174 }; 1175 1176 struct sort_entry sort_mem_iaddr_sym = { 1177 .se_header = "Code Symbol", 1178 .se_cmp = sort__iaddr_cmp, 1179 .se_snprintf = hist_entry__iaddr_snprintf, 1180 .se_width_idx = HISTC_MEM_IADDR_SYMBOL, 1181 }; 1182 1183 struct sort_entry sort_mem_daddr_dso = { 1184 .se_header = "Data Object", 1185 .se_cmp = sort__dso_daddr_cmp, 1186 .se_snprintf = hist_entry__dso_daddr_snprintf, 1187 .se_width_idx = HISTC_MEM_DADDR_SYMBOL, 1188 }; 1189 1190 struct sort_entry sort_mem_locked = { 1191 .se_header = "Locked", 1192 .se_cmp = sort__locked_cmp, 1193 .se_snprintf = hist_entry__locked_snprintf, 1194 .se_width_idx = HISTC_MEM_LOCKED, 1195 }; 1196 1197 struct sort_entry sort_mem_tlb = { 1198 .se_header = "TLB access", 1199 .se_cmp = sort__tlb_cmp, 1200 .se_snprintf = hist_entry__tlb_snprintf, 1201 .se_width_idx = HISTC_MEM_TLB, 1202 }; 1203 1204 struct sort_entry sort_mem_lvl = { 1205 .se_header = "Memory access", 1206 .se_cmp = sort__lvl_cmp, 1207 .se_snprintf = hist_entry__lvl_snprintf, 1208 .se_width_idx = HISTC_MEM_LVL, 1209 }; 1210 1211 struct sort_entry sort_mem_snoop = { 1212 .se_header = "Snoop", 1213 .se_cmp = sort__snoop_cmp, 1214 .se_snprintf = hist_entry__snoop_snprintf, 1215 .se_width_idx = HISTC_MEM_SNOOP, 1216 }; 1217 1218 struct sort_entry sort_mem_dcacheline = { 1219 .se_header = "Data Cacheline", 1220 .se_cmp = sort__dcacheline_cmp, 1221 .se_snprintf = hist_entry__dcacheline_snprintf, 1222 .se_width_idx = HISTC_MEM_DCACHELINE, 1223 }; 1224 1225 static int64_t 1226 sort__abort_cmp(struct hist_entry *left, struct hist_entry *right) 1227 { 1228 if (!left->branch_info || !right->branch_info) 1229 return cmp_null(left->branch_info, right->branch_info); 1230 1231 return left->branch_info->flags.abort != 1232 right->branch_info->flags.abort; 1233 } 1234 1235 static int hist_entry__abort_snprintf(struct hist_entry *he, char *bf, 1236 size_t size, unsigned int width) 1237 { 1238 static const char *out = "N/A"; 1239 1240 if (he->branch_info) { 1241 if (he->branch_info->flags.abort) 1242 out = "A"; 1243 else 1244 out = "."; 1245 } 1246 1247 return repsep_snprintf(bf, size, "%-*s", width, out); 1248 } 1249 1250 struct sort_entry sort_abort = { 1251 .se_header = "Transaction abort", 1252 .se_cmp = sort__abort_cmp, 1253 .se_snprintf = hist_entry__abort_snprintf, 1254 .se_width_idx = HISTC_ABORT, 1255 }; 1256 1257 static int64_t 1258 sort__in_tx_cmp(struct hist_entry *left, struct hist_entry *right) 1259 { 1260 if (!left->branch_info || !right->branch_info) 1261 return cmp_null(left->branch_info, right->branch_info); 1262 1263 return left->branch_info->flags.in_tx != 1264 right->branch_info->flags.in_tx; 1265 } 1266 1267 static int hist_entry__in_tx_snprintf(struct hist_entry *he, char *bf, 1268 size_t size, unsigned int width) 1269 { 1270 static const char *out = "N/A"; 1271 1272 if (he->branch_info) { 1273 if (he->branch_info->flags.in_tx) 1274 out = "T"; 1275 else 1276 out = "."; 1277 } 1278 1279 return repsep_snprintf(bf, size, "%-*s", width, out); 1280 } 1281 1282 struct sort_entry sort_in_tx = { 1283 .se_header = "Branch in transaction", 1284 .se_cmp = sort__in_tx_cmp, 1285 .se_snprintf = hist_entry__in_tx_snprintf, 1286 .se_width_idx = HISTC_IN_TX, 1287 }; 1288 1289 static int64_t 1290 sort__transaction_cmp(struct hist_entry *left, struct hist_entry *right) 1291 { 1292 return left->transaction - right->transaction; 1293 } 1294 1295 static inline char *add_str(char *p, const char *str) 1296 { 1297 strcpy(p, str); 1298 return p + strlen(str); 1299 } 1300 1301 static struct txbit { 1302 unsigned flag; 1303 const char *name; 1304 int skip_for_len; 1305 } txbits[] = { 1306 { PERF_TXN_ELISION, "EL ", 0 }, 1307 { PERF_TXN_TRANSACTION, "TX ", 1 }, 1308 { PERF_TXN_SYNC, "SYNC ", 1 }, 1309 { PERF_TXN_ASYNC, "ASYNC ", 0 }, 1310 { PERF_TXN_RETRY, "RETRY ", 0 }, 1311 { PERF_TXN_CONFLICT, "CON ", 0 }, 1312 { PERF_TXN_CAPACITY_WRITE, "CAP-WRITE ", 1 }, 1313 { PERF_TXN_CAPACITY_READ, "CAP-READ ", 0 }, 1314 { 0, NULL, 0 } 1315 }; 1316 1317 int hist_entry__transaction_len(void) 1318 { 1319 int i; 1320 int len = 0; 1321 1322 for (i = 0; txbits[i].name; i++) { 1323 if (!txbits[i].skip_for_len) 1324 len += strlen(txbits[i].name); 1325 } 1326 len += 4; /* :XX<space> */ 1327 return len; 1328 } 1329 1330 static int hist_entry__transaction_snprintf(struct hist_entry *he, char *bf, 1331 size_t size, unsigned int width) 1332 { 1333 u64 t = he->transaction; 1334 char buf[128]; 1335 char *p = buf; 1336 int i; 1337 1338 buf[0] = 0; 1339 for (i = 0; txbits[i].name; i++) 1340 if (txbits[i].flag & t) 1341 p = add_str(p, txbits[i].name); 1342 if (t && !(t & (PERF_TXN_SYNC|PERF_TXN_ASYNC))) 1343 p = add_str(p, "NEITHER "); 1344 if (t & PERF_TXN_ABORT_MASK) { 1345 sprintf(p, ":%" PRIx64, 1346 (t & PERF_TXN_ABORT_MASK) >> 1347 PERF_TXN_ABORT_SHIFT); 1348 p += strlen(p); 1349 } 1350 1351 return repsep_snprintf(bf, size, "%-*s", width, buf); 1352 } 1353 1354 struct sort_entry sort_transaction = { 1355 .se_header = "Transaction ", 1356 .se_cmp = sort__transaction_cmp, 1357 .se_snprintf = hist_entry__transaction_snprintf, 1358 .se_width_idx = HISTC_TRANSACTION, 1359 }; 1360 1361 struct sort_dimension { 1362 const char *name; 1363 struct sort_entry *entry; 1364 int taken; 1365 }; 1366 1367 #define DIM(d, n, func) [d] = { .name = n, .entry = &(func) } 1368 1369 static struct sort_dimension common_sort_dimensions[] = { 1370 DIM(SORT_PID, "pid", sort_thread), 1371 DIM(SORT_COMM, "comm", sort_comm), 1372 DIM(SORT_DSO, "dso", sort_dso), 1373 DIM(SORT_SYM, "symbol", sort_sym), 1374 DIM(SORT_PARENT, "parent", sort_parent), 1375 DIM(SORT_CPU, "cpu", sort_cpu), 1376 DIM(SORT_SOCKET, "socket", sort_socket), 1377 DIM(SORT_SRCLINE, "srcline", sort_srcline), 1378 DIM(SORT_SRCFILE, "srcfile", sort_srcfile), 1379 DIM(SORT_LOCAL_WEIGHT, "local_weight", sort_local_weight), 1380 DIM(SORT_GLOBAL_WEIGHT, "weight", sort_global_weight), 1381 DIM(SORT_TRANSACTION, "transaction", sort_transaction), 1382 DIM(SORT_TRACE, "trace", sort_trace), 1383 }; 1384 1385 #undef DIM 1386 1387 #define DIM(d, n, func) [d - __SORT_BRANCH_STACK] = { .name = n, .entry = &(func) } 1388 1389 static struct sort_dimension bstack_sort_dimensions[] = { 1390 DIM(SORT_DSO_FROM, "dso_from", sort_dso_from), 1391 DIM(SORT_DSO_TO, "dso_to", sort_dso_to), 1392 DIM(SORT_SYM_FROM, "symbol_from", sort_sym_from), 1393 DIM(SORT_SYM_TO, "symbol_to", sort_sym_to), 1394 DIM(SORT_MISPREDICT, "mispredict", sort_mispredict), 1395 DIM(SORT_IN_TX, "in_tx", sort_in_tx), 1396 DIM(SORT_ABORT, "abort", sort_abort), 1397 DIM(SORT_CYCLES, "cycles", sort_cycles), 1398 }; 1399 1400 #undef DIM 1401 1402 #define DIM(d, n, func) [d - __SORT_MEMORY_MODE] = { .name = n, .entry = &(func) } 1403 1404 static struct sort_dimension memory_sort_dimensions[] = { 1405 DIM(SORT_MEM_DADDR_SYMBOL, "symbol_daddr", sort_mem_daddr_sym), 1406 DIM(SORT_MEM_IADDR_SYMBOL, "symbol_iaddr", sort_mem_iaddr_sym), 1407 DIM(SORT_MEM_DADDR_DSO, "dso_daddr", sort_mem_daddr_dso), 1408 DIM(SORT_MEM_LOCKED, "locked", sort_mem_locked), 1409 DIM(SORT_MEM_TLB, "tlb", sort_mem_tlb), 1410 DIM(SORT_MEM_LVL, "mem", sort_mem_lvl), 1411 DIM(SORT_MEM_SNOOP, "snoop", sort_mem_snoop), 1412 DIM(SORT_MEM_DCACHELINE, "dcacheline", sort_mem_dcacheline), 1413 }; 1414 1415 #undef DIM 1416 1417 struct hpp_dimension { 1418 const char *name; 1419 struct perf_hpp_fmt *fmt; 1420 int taken; 1421 }; 1422 1423 #define DIM(d, n) { .name = n, .fmt = &perf_hpp__format[d], } 1424 1425 static struct hpp_dimension hpp_sort_dimensions[] = { 1426 DIM(PERF_HPP__OVERHEAD, "overhead"), 1427 DIM(PERF_HPP__OVERHEAD_SYS, "overhead_sys"), 1428 DIM(PERF_HPP__OVERHEAD_US, "overhead_us"), 1429 DIM(PERF_HPP__OVERHEAD_GUEST_SYS, "overhead_guest_sys"), 1430 DIM(PERF_HPP__OVERHEAD_GUEST_US, "overhead_guest_us"), 1431 DIM(PERF_HPP__OVERHEAD_ACC, "overhead_children"), 1432 DIM(PERF_HPP__SAMPLES, "sample"), 1433 DIM(PERF_HPP__PERIOD, "period"), 1434 }; 1435 1436 #undef DIM 1437 1438 struct hpp_sort_entry { 1439 struct perf_hpp_fmt hpp; 1440 struct sort_entry *se; 1441 }; 1442 1443 bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b) 1444 { 1445 struct hpp_sort_entry *hse_a; 1446 struct hpp_sort_entry *hse_b; 1447 1448 if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b)) 1449 return false; 1450 1451 hse_a = container_of(a, struct hpp_sort_entry, hpp); 1452 hse_b = container_of(b, struct hpp_sort_entry, hpp); 1453 1454 return hse_a->se == hse_b->se; 1455 } 1456 1457 void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists) 1458 { 1459 struct hpp_sort_entry *hse; 1460 1461 if (!perf_hpp__is_sort_entry(fmt)) 1462 return; 1463 1464 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1465 hists__new_col_len(hists, hse->se->se_width_idx, strlen(fmt->name)); 1466 } 1467 1468 static int __sort__hpp_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 1469 struct perf_evsel *evsel) 1470 { 1471 struct hpp_sort_entry *hse; 1472 size_t len = fmt->user_len; 1473 1474 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1475 1476 if (!len) 1477 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx); 1478 1479 return scnprintf(hpp->buf, hpp->size, "%-*.*s", len, len, fmt->name); 1480 } 1481 1482 static int __sort__hpp_width(struct perf_hpp_fmt *fmt, 1483 struct perf_hpp *hpp __maybe_unused, 1484 struct perf_evsel *evsel) 1485 { 1486 struct hpp_sort_entry *hse; 1487 size_t len = fmt->user_len; 1488 1489 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1490 1491 if (!len) 1492 len = hists__col_len(evsel__hists(evsel), hse->se->se_width_idx); 1493 1494 return len; 1495 } 1496 1497 static int __sort__hpp_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 1498 struct hist_entry *he) 1499 { 1500 struct hpp_sort_entry *hse; 1501 size_t len = fmt->user_len; 1502 1503 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1504 1505 if (!len) 1506 len = hists__col_len(he->hists, hse->se->se_width_idx); 1507 1508 return hse->se->se_snprintf(he, hpp->buf, hpp->size, len); 1509 } 1510 1511 static int64_t __sort__hpp_cmp(struct perf_hpp_fmt *fmt, 1512 struct hist_entry *a, struct hist_entry *b) 1513 { 1514 struct hpp_sort_entry *hse; 1515 1516 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1517 return hse->se->se_cmp(a, b); 1518 } 1519 1520 static int64_t __sort__hpp_collapse(struct perf_hpp_fmt *fmt, 1521 struct hist_entry *a, struct hist_entry *b) 1522 { 1523 struct hpp_sort_entry *hse; 1524 int64_t (*collapse_fn)(struct hist_entry *, struct hist_entry *); 1525 1526 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1527 collapse_fn = hse->se->se_collapse ?: hse->se->se_cmp; 1528 return collapse_fn(a, b); 1529 } 1530 1531 static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt, 1532 struct hist_entry *a, struct hist_entry *b) 1533 { 1534 struct hpp_sort_entry *hse; 1535 int64_t (*sort_fn)(struct hist_entry *, struct hist_entry *); 1536 1537 hse = container_of(fmt, struct hpp_sort_entry, hpp); 1538 sort_fn = hse->se->se_sort ?: hse->se->se_cmp; 1539 return sort_fn(a, b); 1540 } 1541 1542 static struct hpp_sort_entry * 1543 __sort_dimension__alloc_hpp(struct sort_dimension *sd) 1544 { 1545 struct hpp_sort_entry *hse; 1546 1547 hse = malloc(sizeof(*hse)); 1548 if (hse == NULL) { 1549 pr_err("Memory allocation failed\n"); 1550 return NULL; 1551 } 1552 1553 hse->se = sd->entry; 1554 hse->hpp.name = sd->entry->se_header; 1555 hse->hpp.header = __sort__hpp_header; 1556 hse->hpp.width = __sort__hpp_width; 1557 hse->hpp.entry = __sort__hpp_entry; 1558 hse->hpp.color = NULL; 1559 1560 hse->hpp.cmp = __sort__hpp_cmp; 1561 hse->hpp.collapse = __sort__hpp_collapse; 1562 hse->hpp.sort = __sort__hpp_sort; 1563 1564 INIT_LIST_HEAD(&hse->hpp.list); 1565 INIT_LIST_HEAD(&hse->hpp.sort_list); 1566 hse->hpp.elide = false; 1567 hse->hpp.len = 0; 1568 hse->hpp.user_len = 0; 1569 1570 return hse; 1571 } 1572 1573 bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format) 1574 { 1575 return format->header == __sort__hpp_header; 1576 } 1577 1578 static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd) 1579 { 1580 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd); 1581 1582 if (hse == NULL) 1583 return -1; 1584 1585 perf_hpp__register_sort_field(&hse->hpp); 1586 return 0; 1587 } 1588 1589 static int __sort_dimension__add_hpp_output(struct sort_dimension *sd) 1590 { 1591 struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd); 1592 1593 if (hse == NULL) 1594 return -1; 1595 1596 perf_hpp__column_register(&hse->hpp); 1597 return 0; 1598 } 1599 1600 struct hpp_dynamic_entry { 1601 struct perf_hpp_fmt hpp; 1602 struct perf_evsel *evsel; 1603 struct format_field *field; 1604 unsigned dynamic_len; 1605 bool raw_trace; 1606 }; 1607 1608 static int hde_width(struct hpp_dynamic_entry *hde) 1609 { 1610 if (!hde->hpp.len) { 1611 int len = hde->dynamic_len; 1612 int namelen = strlen(hde->field->name); 1613 int fieldlen = hde->field->size; 1614 1615 if (namelen > len) 1616 len = namelen; 1617 1618 if (!(hde->field->flags & FIELD_IS_STRING)) { 1619 /* length for print hex numbers */ 1620 fieldlen = hde->field->size * 2 + 2; 1621 } 1622 if (fieldlen > len) 1623 len = fieldlen; 1624 1625 hde->hpp.len = len; 1626 } 1627 return hde->hpp.len; 1628 } 1629 1630 static void update_dynamic_len(struct hpp_dynamic_entry *hde, 1631 struct hist_entry *he) 1632 { 1633 char *str, *pos; 1634 struct format_field *field = hde->field; 1635 size_t namelen; 1636 bool last = false; 1637 1638 if (hde->raw_trace) 1639 return; 1640 1641 /* parse pretty print result and update max length */ 1642 if (!he->trace_output) 1643 he->trace_output = get_trace_output(he); 1644 1645 namelen = strlen(field->name); 1646 str = he->trace_output; 1647 1648 while (str) { 1649 pos = strchr(str, ' '); 1650 if (pos == NULL) { 1651 last = true; 1652 pos = str + strlen(str); 1653 } 1654 1655 if (!strncmp(str, field->name, namelen)) { 1656 size_t len; 1657 1658 str += namelen + 1; 1659 len = pos - str; 1660 1661 if (len > hde->dynamic_len) 1662 hde->dynamic_len = len; 1663 break; 1664 } 1665 1666 if (last) 1667 str = NULL; 1668 else 1669 str = pos + 1; 1670 } 1671 } 1672 1673 static int __sort__hde_header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 1674 struct perf_evsel *evsel __maybe_unused) 1675 { 1676 struct hpp_dynamic_entry *hde; 1677 size_t len = fmt->user_len; 1678 1679 hde = container_of(fmt, struct hpp_dynamic_entry, hpp); 1680 1681 if (!len) 1682 len = hde_width(hde); 1683 1684 return scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, hde->field->name); 1685 } 1686 1687 static int __sort__hde_width(struct perf_hpp_fmt *fmt, 1688 struct perf_hpp *hpp __maybe_unused, 1689 struct perf_evsel *evsel __maybe_unused) 1690 { 1691 struct hpp_dynamic_entry *hde; 1692 size_t len = fmt->user_len; 1693 1694 hde = container_of(fmt, struct hpp_dynamic_entry, hpp); 1695 1696 if (!len) 1697 len = hde_width(hde); 1698 1699 return len; 1700 } 1701 1702 bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists) 1703 { 1704 struct hpp_dynamic_entry *hde; 1705 1706 hde = container_of(fmt, struct hpp_dynamic_entry, hpp); 1707 1708 return hists_to_evsel(hists) == hde->evsel; 1709 } 1710 1711 static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, 1712 struct hist_entry *he) 1713 { 1714 struct hpp_dynamic_entry *hde; 1715 size_t len = fmt->user_len; 1716 char *str, *pos; 1717 struct format_field *field; 1718 size_t namelen; 1719 bool last = false; 1720 int ret; 1721 1722 hde = container_of(fmt, struct hpp_dynamic_entry, hpp); 1723 1724 if (!len) 1725 len = hde_width(hde); 1726 1727 if (hde->raw_trace) 1728 goto raw_field; 1729 1730 field = hde->field; 1731 namelen = strlen(field->name); 1732 str = he->trace_output; 1733 1734 while (str) { 1735 pos = strchr(str, ' '); 1736 if (pos == NULL) { 1737 last = true; 1738 pos = str + strlen(str); 1739 } 1740 1741 if (!strncmp(str, field->name, namelen)) { 1742 str += namelen + 1; 1743 str = strndup(str, pos - str); 1744 1745 if (str == NULL) 1746 return scnprintf(hpp->buf, hpp->size, 1747 "%*.*s", len, len, "ERROR"); 1748 break; 1749 } 1750 1751 if (last) 1752 str = NULL; 1753 else 1754 str = pos + 1; 1755 } 1756 1757 if (str == NULL) { 1758 struct trace_seq seq; 1759 raw_field: 1760 trace_seq_init(&seq); 1761 pevent_print_field(&seq, he->raw_data, hde->field); 1762 str = seq.buffer; 1763 } 1764 1765 ret = scnprintf(hpp->buf, hpp->size, "%*.*s", len, len, str); 1766 free(str); 1767 return ret; 1768 } 1769 1770 static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt, 1771 struct hist_entry *a, struct hist_entry *b) 1772 { 1773 struct hpp_dynamic_entry *hde; 1774 struct format_field *field; 1775 unsigned offset, size; 1776 1777 hde = container_of(fmt, struct hpp_dynamic_entry, hpp); 1778 1779 field = hde->field; 1780 if (field->flags & FIELD_IS_DYNAMIC) { 1781 unsigned long long dyn; 1782 1783 pevent_read_number_field(field, a->raw_data, &dyn); 1784 offset = dyn & 0xffff; 1785 size = (dyn >> 16) & 0xffff; 1786 1787 /* record max width for output */ 1788 if (size > hde->dynamic_len) 1789 hde->dynamic_len = size; 1790 } else { 1791 offset = field->offset; 1792 size = field->size; 1793 1794 update_dynamic_len(hde, a); 1795 update_dynamic_len(hde, b); 1796 } 1797 1798 return memcmp(a->raw_data + offset, b->raw_data + offset, size); 1799 } 1800 1801 bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt) 1802 { 1803 return fmt->cmp == __sort__hde_cmp; 1804 } 1805 1806 static struct hpp_dynamic_entry * 1807 __alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field) 1808 { 1809 struct hpp_dynamic_entry *hde; 1810 1811 hde = malloc(sizeof(*hde)); 1812 if (hde == NULL) { 1813 pr_debug("Memory allocation failed\n"); 1814 return NULL; 1815 } 1816 1817 hde->evsel = evsel; 1818 hde->field = field; 1819 hde->dynamic_len = 0; 1820 1821 hde->hpp.name = field->name; 1822 hde->hpp.header = __sort__hde_header; 1823 hde->hpp.width = __sort__hde_width; 1824 hde->hpp.entry = __sort__hde_entry; 1825 hde->hpp.color = NULL; 1826 1827 hde->hpp.cmp = __sort__hde_cmp; 1828 hde->hpp.collapse = __sort__hde_cmp; 1829 hde->hpp.sort = __sort__hde_cmp; 1830 1831 INIT_LIST_HEAD(&hde->hpp.list); 1832 INIT_LIST_HEAD(&hde->hpp.sort_list); 1833 hde->hpp.elide = false; 1834 hde->hpp.len = 0; 1835 hde->hpp.user_len = 0; 1836 1837 return hde; 1838 } 1839 1840 static int parse_field_name(char *str, char **event, char **field, char **opt) 1841 { 1842 char *event_name, *field_name, *opt_name; 1843 1844 event_name = str; 1845 field_name = strchr(str, '.'); 1846 1847 if (field_name) { 1848 *field_name++ = '\0'; 1849 } else { 1850 event_name = NULL; 1851 field_name = str; 1852 } 1853 1854 opt_name = strchr(field_name, '/'); 1855 if (opt_name) 1856 *opt_name++ = '\0'; 1857 1858 *event = event_name; 1859 *field = field_name; 1860 *opt = opt_name; 1861 1862 return 0; 1863 } 1864 1865 /* find match evsel using a given event name. The event name can be: 1866 * 1. '%' + event index (e.g. '%1' for first event) 1867 * 2. full event name (e.g. sched:sched_switch) 1868 * 3. partial event name (should not contain ':') 1869 */ 1870 static struct perf_evsel *find_evsel(struct perf_evlist *evlist, char *event_name) 1871 { 1872 struct perf_evsel *evsel = NULL; 1873 struct perf_evsel *pos; 1874 bool full_name; 1875 1876 /* case 1 */ 1877 if (event_name[0] == '%') { 1878 int nr = strtol(event_name+1, NULL, 0); 1879 1880 if (nr > evlist->nr_entries) 1881 return NULL; 1882 1883 evsel = perf_evlist__first(evlist); 1884 while (--nr > 0) 1885 evsel = perf_evsel__next(evsel); 1886 1887 return evsel; 1888 } 1889 1890 full_name = !!strchr(event_name, ':'); 1891 evlist__for_each(evlist, pos) { 1892 /* case 2 */ 1893 if (full_name && !strcmp(pos->name, event_name)) 1894 return pos; 1895 /* case 3 */ 1896 if (!full_name && strstr(pos->name, event_name)) { 1897 if (evsel) { 1898 pr_debug("'%s' event is ambiguous: it can be %s or %s\n", 1899 event_name, evsel->name, pos->name); 1900 return NULL; 1901 } 1902 evsel = pos; 1903 } 1904 } 1905 1906 return evsel; 1907 } 1908 1909 static int __dynamic_dimension__add(struct perf_evsel *evsel, 1910 struct format_field *field, 1911 bool raw_trace) 1912 { 1913 struct hpp_dynamic_entry *hde; 1914 1915 hde = __alloc_dynamic_entry(evsel, field); 1916 if (hde == NULL) 1917 return -ENOMEM; 1918 1919 hde->raw_trace = raw_trace; 1920 1921 perf_hpp__register_sort_field(&hde->hpp); 1922 return 0; 1923 } 1924 1925 static int add_evsel_fields(struct perf_evsel *evsel, bool raw_trace) 1926 { 1927 int ret; 1928 struct format_field *field; 1929 1930 field = evsel->tp_format->format.fields; 1931 while (field) { 1932 ret = __dynamic_dimension__add(evsel, field, raw_trace); 1933 if (ret < 0) 1934 return ret; 1935 1936 field = field->next; 1937 } 1938 return 0; 1939 } 1940 1941 static int add_all_dynamic_fields(struct perf_evlist *evlist, bool raw_trace) 1942 { 1943 int ret; 1944 struct perf_evsel *evsel; 1945 1946 evlist__for_each(evlist, evsel) { 1947 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) 1948 continue; 1949 1950 ret = add_evsel_fields(evsel, raw_trace); 1951 if (ret < 0) 1952 return ret; 1953 } 1954 return 0; 1955 } 1956 1957 static int add_all_matching_fields(struct perf_evlist *evlist, 1958 char *field_name, bool raw_trace) 1959 { 1960 int ret = -ESRCH; 1961 struct perf_evsel *evsel; 1962 struct format_field *field; 1963 1964 evlist__for_each(evlist, evsel) { 1965 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) 1966 continue; 1967 1968 field = pevent_find_any_field(evsel->tp_format, field_name); 1969 if (field == NULL) 1970 continue; 1971 1972 ret = __dynamic_dimension__add(evsel, field, raw_trace); 1973 if (ret < 0) 1974 break; 1975 } 1976 return ret; 1977 } 1978 1979 static int add_dynamic_entry(struct perf_evlist *evlist, const char *tok) 1980 { 1981 char *str, *event_name, *field_name, *opt_name; 1982 struct perf_evsel *evsel; 1983 struct format_field *field; 1984 bool raw_trace = symbol_conf.raw_trace; 1985 int ret = 0; 1986 1987 if (evlist == NULL) 1988 return -ENOENT; 1989 1990 str = strdup(tok); 1991 if (str == NULL) 1992 return -ENOMEM; 1993 1994 if (parse_field_name(str, &event_name, &field_name, &opt_name) < 0) { 1995 ret = -EINVAL; 1996 goto out; 1997 } 1998 1999 if (opt_name) { 2000 if (strcmp(opt_name, "raw")) { 2001 pr_debug("unsupported field option %s\n", opt_name); 2002 ret = -EINVAL; 2003 goto out; 2004 } 2005 raw_trace = true; 2006 } 2007 2008 if (!strcmp(field_name, "trace_fields")) { 2009 ret = add_all_dynamic_fields(evlist, raw_trace); 2010 goto out; 2011 } 2012 2013 if (event_name == NULL) { 2014 ret = add_all_matching_fields(evlist, field_name, raw_trace); 2015 goto out; 2016 } 2017 2018 evsel = find_evsel(evlist, event_name); 2019 if (evsel == NULL) { 2020 pr_debug("Cannot find event: %s\n", event_name); 2021 ret = -ENOENT; 2022 goto out; 2023 } 2024 2025 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { 2026 pr_debug("%s is not a tracepoint event\n", event_name); 2027 ret = -EINVAL; 2028 goto out; 2029 } 2030 2031 if (!strcmp(field_name, "*")) { 2032 ret = add_evsel_fields(evsel, raw_trace); 2033 } else { 2034 field = pevent_find_any_field(evsel->tp_format, field_name); 2035 if (field == NULL) { 2036 pr_debug("Cannot find event field for %s.%s\n", 2037 event_name, field_name); 2038 return -ENOENT; 2039 } 2040 2041 ret = __dynamic_dimension__add(evsel, field, raw_trace); 2042 } 2043 2044 out: 2045 free(str); 2046 return ret; 2047 } 2048 2049 static int __sort_dimension__add(struct sort_dimension *sd) 2050 { 2051 if (sd->taken) 2052 return 0; 2053 2054 if (__sort_dimension__add_hpp_sort(sd) < 0) 2055 return -1; 2056 2057 if (sd->entry->se_collapse) 2058 sort__need_collapse = 1; 2059 2060 sd->taken = 1; 2061 2062 return 0; 2063 } 2064 2065 static int __hpp_dimension__add(struct hpp_dimension *hd) 2066 { 2067 if (!hd->taken) { 2068 hd->taken = 1; 2069 2070 perf_hpp__register_sort_field(hd->fmt); 2071 } 2072 return 0; 2073 } 2074 2075 static int __sort_dimension__add_output(struct sort_dimension *sd) 2076 { 2077 if (sd->taken) 2078 return 0; 2079 2080 if (__sort_dimension__add_hpp_output(sd) < 0) 2081 return -1; 2082 2083 sd->taken = 1; 2084 return 0; 2085 } 2086 2087 static int __hpp_dimension__add_output(struct hpp_dimension *hd) 2088 { 2089 if (!hd->taken) { 2090 hd->taken = 1; 2091 2092 perf_hpp__column_register(hd->fmt); 2093 } 2094 return 0; 2095 } 2096 2097 int hpp_dimension__add_output(unsigned col) 2098 { 2099 BUG_ON(col >= PERF_HPP__MAX_INDEX); 2100 return __hpp_dimension__add_output(&hpp_sort_dimensions[col]); 2101 } 2102 2103 static int sort_dimension__add(const char *tok, 2104 struct perf_evlist *evlist __maybe_unused) 2105 { 2106 unsigned int i; 2107 2108 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) { 2109 struct sort_dimension *sd = &common_sort_dimensions[i]; 2110 2111 if (strncasecmp(tok, sd->name, strlen(tok))) 2112 continue; 2113 2114 if (sd->entry == &sort_parent) { 2115 int ret = regcomp(&parent_regex, parent_pattern, REG_EXTENDED); 2116 if (ret) { 2117 char err[BUFSIZ]; 2118 2119 regerror(ret, &parent_regex, err, sizeof(err)); 2120 pr_err("Invalid regex: %s\n%s", parent_pattern, err); 2121 return -EINVAL; 2122 } 2123 sort__has_parent = 1; 2124 } else if (sd->entry == &sort_sym) { 2125 sort__has_sym = 1; 2126 /* 2127 * perf diff displays the performance difference amongst 2128 * two or more perf.data files. Those files could come 2129 * from different binaries. So we should not compare 2130 * their ips, but the name of symbol. 2131 */ 2132 if (sort__mode == SORT_MODE__DIFF) 2133 sd->entry->se_collapse = sort__sym_sort; 2134 2135 } else if (sd->entry == &sort_dso) { 2136 sort__has_dso = 1; 2137 } else if (sd->entry == &sort_socket) { 2138 sort__has_socket = 1; 2139 } 2140 2141 return __sort_dimension__add(sd); 2142 } 2143 2144 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { 2145 struct hpp_dimension *hd = &hpp_sort_dimensions[i]; 2146 2147 if (strncasecmp(tok, hd->name, strlen(tok))) 2148 continue; 2149 2150 return __hpp_dimension__add(hd); 2151 } 2152 2153 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 2154 struct sort_dimension *sd = &bstack_sort_dimensions[i]; 2155 2156 if (strncasecmp(tok, sd->name, strlen(tok))) 2157 continue; 2158 2159 if (sort__mode != SORT_MODE__BRANCH) 2160 return -EINVAL; 2161 2162 if (sd->entry == &sort_sym_from || sd->entry == &sort_sym_to) 2163 sort__has_sym = 1; 2164 2165 __sort_dimension__add(sd); 2166 return 0; 2167 } 2168 2169 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) { 2170 struct sort_dimension *sd = &memory_sort_dimensions[i]; 2171 2172 if (strncasecmp(tok, sd->name, strlen(tok))) 2173 continue; 2174 2175 if (sort__mode != SORT_MODE__MEMORY) 2176 return -EINVAL; 2177 2178 if (sd->entry == &sort_mem_daddr_sym) 2179 sort__has_sym = 1; 2180 2181 __sort_dimension__add(sd); 2182 return 0; 2183 } 2184 2185 if (!add_dynamic_entry(evlist, tok)) 2186 return 0; 2187 2188 return -ESRCH; 2189 } 2190 2191 static const char *get_default_sort_order(struct perf_evlist *evlist) 2192 { 2193 const char *default_sort_orders[] = { 2194 default_sort_order, 2195 default_branch_sort_order, 2196 default_mem_sort_order, 2197 default_top_sort_order, 2198 default_diff_sort_order, 2199 default_tracepoint_sort_order, 2200 }; 2201 bool use_trace = true; 2202 struct perf_evsel *evsel; 2203 2204 BUG_ON(sort__mode >= ARRAY_SIZE(default_sort_orders)); 2205 2206 if (evlist == NULL) 2207 goto out_no_evlist; 2208 2209 evlist__for_each(evlist, evsel) { 2210 if (evsel->attr.type != PERF_TYPE_TRACEPOINT) { 2211 use_trace = false; 2212 break; 2213 } 2214 } 2215 2216 if (use_trace) { 2217 sort__mode = SORT_MODE__TRACEPOINT; 2218 if (symbol_conf.raw_trace) 2219 return "trace_fields"; 2220 } 2221 out_no_evlist: 2222 return default_sort_orders[sort__mode]; 2223 } 2224 2225 static int setup_sort_order(struct perf_evlist *evlist) 2226 { 2227 char *new_sort_order; 2228 2229 /* 2230 * Append '+'-prefixed sort order to the default sort 2231 * order string. 2232 */ 2233 if (!sort_order || is_strict_order(sort_order)) 2234 return 0; 2235 2236 if (sort_order[1] == '\0') { 2237 error("Invalid --sort key: `+'"); 2238 return -EINVAL; 2239 } 2240 2241 /* 2242 * We allocate new sort_order string, but we never free it, 2243 * because it's checked over the rest of the code. 2244 */ 2245 if (asprintf(&new_sort_order, "%s,%s", 2246 get_default_sort_order(evlist), sort_order + 1) < 0) { 2247 error("Not enough memory to set up --sort"); 2248 return -ENOMEM; 2249 } 2250 2251 sort_order = new_sort_order; 2252 return 0; 2253 } 2254 2255 /* 2256 * Adds 'pre,' prefix into 'str' is 'pre' is 2257 * not already part of 'str'. 2258 */ 2259 static char *prefix_if_not_in(const char *pre, char *str) 2260 { 2261 char *n; 2262 2263 if (!str || strstr(str, pre)) 2264 return str; 2265 2266 if (asprintf(&n, "%s,%s", pre, str) < 0) 2267 return NULL; 2268 2269 free(str); 2270 return n; 2271 } 2272 2273 static char *setup_overhead(char *keys) 2274 { 2275 keys = prefix_if_not_in("overhead", keys); 2276 2277 if (symbol_conf.cumulate_callchain) 2278 keys = prefix_if_not_in("overhead_children", keys); 2279 2280 return keys; 2281 } 2282 2283 static int __setup_sorting(struct perf_evlist *evlist) 2284 { 2285 char *tmp, *tok, *str; 2286 const char *sort_keys; 2287 int ret = 0; 2288 2289 ret = setup_sort_order(evlist); 2290 if (ret) 2291 return ret; 2292 2293 sort_keys = sort_order; 2294 if (sort_keys == NULL) { 2295 if (is_strict_order(field_order)) { 2296 /* 2297 * If user specified field order but no sort order, 2298 * we'll honor it and not add default sort orders. 2299 */ 2300 return 0; 2301 } 2302 2303 sort_keys = get_default_sort_order(evlist); 2304 } 2305 2306 str = strdup(sort_keys); 2307 if (str == NULL) { 2308 error("Not enough memory to setup sort keys"); 2309 return -ENOMEM; 2310 } 2311 2312 /* 2313 * Prepend overhead fields for backward compatibility. 2314 */ 2315 if (!is_strict_order(field_order)) { 2316 str = setup_overhead(str); 2317 if (str == NULL) { 2318 error("Not enough memory to setup overhead keys"); 2319 return -ENOMEM; 2320 } 2321 } 2322 2323 for (tok = strtok_r(str, ", ", &tmp); 2324 tok; tok = strtok_r(NULL, ", ", &tmp)) { 2325 ret = sort_dimension__add(tok, evlist); 2326 if (ret == -EINVAL) { 2327 error("Invalid --sort key: `%s'", tok); 2328 break; 2329 } else if (ret == -ESRCH) { 2330 error("Unknown --sort key: `%s'", tok); 2331 break; 2332 } 2333 } 2334 2335 free(str); 2336 return ret; 2337 } 2338 2339 void perf_hpp__set_elide(int idx, bool elide) 2340 { 2341 struct perf_hpp_fmt *fmt; 2342 struct hpp_sort_entry *hse; 2343 2344 perf_hpp__for_each_format(fmt) { 2345 if (!perf_hpp__is_sort_entry(fmt)) 2346 continue; 2347 2348 hse = container_of(fmt, struct hpp_sort_entry, hpp); 2349 if (hse->se->se_width_idx == idx) { 2350 fmt->elide = elide; 2351 break; 2352 } 2353 } 2354 } 2355 2356 static bool __get_elide(struct strlist *list, const char *list_name, FILE *fp) 2357 { 2358 if (list && strlist__nr_entries(list) == 1) { 2359 if (fp != NULL) 2360 fprintf(fp, "# %s: %s\n", list_name, 2361 strlist__entry(list, 0)->s); 2362 return true; 2363 } 2364 return false; 2365 } 2366 2367 static bool get_elide(int idx, FILE *output) 2368 { 2369 switch (idx) { 2370 case HISTC_SYMBOL: 2371 return __get_elide(symbol_conf.sym_list, "symbol", output); 2372 case HISTC_DSO: 2373 return __get_elide(symbol_conf.dso_list, "dso", output); 2374 case HISTC_COMM: 2375 return __get_elide(symbol_conf.comm_list, "comm", output); 2376 default: 2377 break; 2378 } 2379 2380 if (sort__mode != SORT_MODE__BRANCH) 2381 return false; 2382 2383 switch (idx) { 2384 case HISTC_SYMBOL_FROM: 2385 return __get_elide(symbol_conf.sym_from_list, "sym_from", output); 2386 case HISTC_SYMBOL_TO: 2387 return __get_elide(symbol_conf.sym_to_list, "sym_to", output); 2388 case HISTC_DSO_FROM: 2389 return __get_elide(symbol_conf.dso_from_list, "dso_from", output); 2390 case HISTC_DSO_TO: 2391 return __get_elide(symbol_conf.dso_to_list, "dso_to", output); 2392 default: 2393 break; 2394 } 2395 2396 return false; 2397 } 2398 2399 void sort__setup_elide(FILE *output) 2400 { 2401 struct perf_hpp_fmt *fmt; 2402 struct hpp_sort_entry *hse; 2403 2404 perf_hpp__for_each_format(fmt) { 2405 if (!perf_hpp__is_sort_entry(fmt)) 2406 continue; 2407 2408 hse = container_of(fmt, struct hpp_sort_entry, hpp); 2409 fmt->elide = get_elide(hse->se->se_width_idx, output); 2410 } 2411 2412 /* 2413 * It makes no sense to elide all of sort entries. 2414 * Just revert them to show up again. 2415 */ 2416 perf_hpp__for_each_format(fmt) { 2417 if (!perf_hpp__is_sort_entry(fmt)) 2418 continue; 2419 2420 if (!fmt->elide) 2421 return; 2422 } 2423 2424 perf_hpp__for_each_format(fmt) { 2425 if (!perf_hpp__is_sort_entry(fmt)) 2426 continue; 2427 2428 fmt->elide = false; 2429 } 2430 } 2431 2432 static int output_field_add(char *tok) 2433 { 2434 unsigned int i; 2435 2436 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) { 2437 struct sort_dimension *sd = &common_sort_dimensions[i]; 2438 2439 if (strncasecmp(tok, sd->name, strlen(tok))) 2440 continue; 2441 2442 return __sort_dimension__add_output(sd); 2443 } 2444 2445 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) { 2446 struct hpp_dimension *hd = &hpp_sort_dimensions[i]; 2447 2448 if (strncasecmp(tok, hd->name, strlen(tok))) 2449 continue; 2450 2451 return __hpp_dimension__add_output(hd); 2452 } 2453 2454 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) { 2455 struct sort_dimension *sd = &bstack_sort_dimensions[i]; 2456 2457 if (strncasecmp(tok, sd->name, strlen(tok))) 2458 continue; 2459 2460 return __sort_dimension__add_output(sd); 2461 } 2462 2463 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) { 2464 struct sort_dimension *sd = &memory_sort_dimensions[i]; 2465 2466 if (strncasecmp(tok, sd->name, strlen(tok))) 2467 continue; 2468 2469 return __sort_dimension__add_output(sd); 2470 } 2471 2472 return -ESRCH; 2473 } 2474 2475 static void reset_dimensions(void) 2476 { 2477 unsigned int i; 2478 2479 for (i = 0; i < ARRAY_SIZE(common_sort_dimensions); i++) 2480 common_sort_dimensions[i].taken = 0; 2481 2482 for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) 2483 hpp_sort_dimensions[i].taken = 0; 2484 2485 for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) 2486 bstack_sort_dimensions[i].taken = 0; 2487 2488 for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) 2489 memory_sort_dimensions[i].taken = 0; 2490 } 2491 2492 bool is_strict_order(const char *order) 2493 { 2494 return order && (*order != '+'); 2495 } 2496 2497 static int __setup_output_field(void) 2498 { 2499 char *tmp, *tok, *str, *strp; 2500 int ret = -EINVAL; 2501 2502 if (field_order == NULL) 2503 return 0; 2504 2505 strp = str = strdup(field_order); 2506 if (str == NULL) { 2507 error("Not enough memory to setup output fields"); 2508 return -ENOMEM; 2509 } 2510 2511 if (!is_strict_order(field_order)) 2512 strp++; 2513 2514 if (!strlen(strp)) { 2515 error("Invalid --fields key: `+'"); 2516 goto out; 2517 } 2518 2519 for (tok = strtok_r(strp, ", ", &tmp); 2520 tok; tok = strtok_r(NULL, ", ", &tmp)) { 2521 ret = output_field_add(tok); 2522 if (ret == -EINVAL) { 2523 error("Invalid --fields key: `%s'", tok); 2524 break; 2525 } else if (ret == -ESRCH) { 2526 error("Unknown --fields key: `%s'", tok); 2527 break; 2528 } 2529 } 2530 2531 out: 2532 free(str); 2533 return ret; 2534 } 2535 2536 int setup_sorting(struct perf_evlist *evlist) 2537 { 2538 int err; 2539 2540 err = __setup_sorting(evlist); 2541 if (err < 0) 2542 return err; 2543 2544 if (parent_pattern != default_parent_pattern) { 2545 err = sort_dimension__add("parent", evlist); 2546 if (err < 0) 2547 return err; 2548 } 2549 2550 reset_dimensions(); 2551 2552 /* 2553 * perf diff doesn't use default hpp output fields. 2554 */ 2555 if (sort__mode != SORT_MODE__DIFF) 2556 perf_hpp__init(); 2557 2558 err = __setup_output_field(); 2559 if (err < 0) 2560 return err; 2561 2562 /* copy sort keys to output fields */ 2563 perf_hpp__setup_output_field(); 2564 /* and then copy output fields to sort keys */ 2565 perf_hpp__append_sort_keys(); 2566 2567 return 0; 2568 } 2569 2570 void reset_output_field(void) 2571 { 2572 sort__need_collapse = 0; 2573 sort__has_parent = 0; 2574 sort__has_sym = 0; 2575 sort__has_dso = 0; 2576 2577 field_order = NULL; 2578 sort_order = NULL; 2579 2580 reset_dimensions(); 2581 perf_hpp__reset_output_field(); 2582 } 2583