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