1 #include "annotate.h" 2 #include "util.h" 3 #include "build-id.h" 4 #include "hist.h" 5 #include "session.h" 6 #include "sort.h" 7 #include <math.h> 8 9 static bool hists__filter_entry_by_dso(struct hists *hists, 10 struct hist_entry *he); 11 static bool hists__filter_entry_by_thread(struct hists *hists, 12 struct hist_entry *he); 13 static bool hists__filter_entry_by_symbol(struct hists *hists, 14 struct hist_entry *he); 15 16 enum hist_filter { 17 HIST_FILTER__DSO, 18 HIST_FILTER__THREAD, 19 HIST_FILTER__PARENT, 20 HIST_FILTER__SYMBOL, 21 }; 22 23 struct callchain_param callchain_param = { 24 .mode = CHAIN_GRAPH_REL, 25 .min_percent = 0.5, 26 .order = ORDER_CALLEE 27 }; 28 29 u16 hists__col_len(struct hists *hists, enum hist_column col) 30 { 31 return hists->col_len[col]; 32 } 33 34 void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len) 35 { 36 hists->col_len[col] = len; 37 } 38 39 bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len) 40 { 41 if (len > hists__col_len(hists, col)) { 42 hists__set_col_len(hists, col, len); 43 return true; 44 } 45 return false; 46 } 47 48 static void hists__reset_col_len(struct hists *hists) 49 { 50 enum hist_column col; 51 52 for (col = 0; col < HISTC_NR_COLS; ++col) 53 hists__set_col_len(hists, col, 0); 54 } 55 56 static void hists__set_unres_dso_col_len(struct hists *hists, int dso) 57 { 58 const unsigned int unresolved_col_width = BITS_PER_LONG / 4; 59 60 if (hists__col_len(hists, dso) < unresolved_col_width && 61 !symbol_conf.col_width_list_str && !symbol_conf.field_sep && 62 !symbol_conf.dso_list) 63 hists__set_col_len(hists, dso, unresolved_col_width); 64 } 65 66 static void hists__calc_col_len(struct hists *hists, struct hist_entry *h) 67 { 68 const unsigned int unresolved_col_width = BITS_PER_LONG / 4; 69 u16 len; 70 71 if (h->ms.sym) 72 hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4); 73 else 74 hists__set_unres_dso_col_len(hists, HISTC_DSO); 75 76 len = thread__comm_len(h->thread); 77 if (hists__new_col_len(hists, HISTC_COMM, len)) 78 hists__set_col_len(hists, HISTC_THREAD, len + 6); 79 80 if (h->ms.map) { 81 len = dso__name_len(h->ms.map->dso); 82 hists__new_col_len(hists, HISTC_DSO, len); 83 } 84 85 if (h->branch_info) { 86 int symlen; 87 /* 88 * +4 accounts for '[x] ' priv level info 89 * +2 account of 0x prefix on raw addresses 90 */ 91 if (h->branch_info->from.sym) { 92 symlen = (int)h->branch_info->from.sym->namelen + 4; 93 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen); 94 95 symlen = dso__name_len(h->branch_info->from.map->dso); 96 hists__new_col_len(hists, HISTC_DSO_FROM, symlen); 97 } else { 98 symlen = unresolved_col_width + 4 + 2; 99 hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen); 100 hists__set_unres_dso_col_len(hists, HISTC_DSO_FROM); 101 } 102 103 if (h->branch_info->to.sym) { 104 symlen = (int)h->branch_info->to.sym->namelen + 4; 105 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen); 106 107 symlen = dso__name_len(h->branch_info->to.map->dso); 108 hists__new_col_len(hists, HISTC_DSO_TO, symlen); 109 } else { 110 symlen = unresolved_col_width + 4 + 2; 111 hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen); 112 hists__set_unres_dso_col_len(hists, HISTC_DSO_TO); 113 } 114 } 115 } 116 117 static void hist_entry__add_cpumode_period(struct hist_entry *he, 118 unsigned int cpumode, u64 period) 119 { 120 switch (cpumode) { 121 case PERF_RECORD_MISC_KERNEL: 122 he->period_sys += period; 123 break; 124 case PERF_RECORD_MISC_USER: 125 he->period_us += period; 126 break; 127 case PERF_RECORD_MISC_GUEST_KERNEL: 128 he->period_guest_sys += period; 129 break; 130 case PERF_RECORD_MISC_GUEST_USER: 131 he->period_guest_us += period; 132 break; 133 default: 134 break; 135 } 136 } 137 138 static void hist_entry__decay(struct hist_entry *he) 139 { 140 he->period = (he->period * 7) / 8; 141 he->nr_events = (he->nr_events * 7) / 8; 142 } 143 144 static bool hists__decay_entry(struct hists *hists, struct hist_entry *he) 145 { 146 u64 prev_period = he->period; 147 148 if (prev_period == 0) 149 return true; 150 151 hist_entry__decay(he); 152 153 if (!he->filtered) 154 hists->stats.total_period -= prev_period - he->period; 155 156 return he->period == 0; 157 } 158 159 static void __hists__decay_entries(struct hists *hists, bool zap_user, 160 bool zap_kernel, bool threaded) 161 { 162 struct rb_node *next = rb_first(&hists->entries); 163 struct hist_entry *n; 164 165 while (next) { 166 n = rb_entry(next, struct hist_entry, rb_node); 167 next = rb_next(&n->rb_node); 168 /* 169 * We may be annotating this, for instance, so keep it here in 170 * case some it gets new samples, we'll eventually free it when 171 * the user stops browsing and it agains gets fully decayed. 172 */ 173 if (((zap_user && n->level == '.') || 174 (zap_kernel && n->level != '.') || 175 hists__decay_entry(hists, n)) && 176 !n->used) { 177 rb_erase(&n->rb_node, &hists->entries); 178 179 if (sort__need_collapse || threaded) 180 rb_erase(&n->rb_node_in, &hists->entries_collapsed); 181 182 hist_entry__free(n); 183 --hists->nr_entries; 184 } 185 } 186 } 187 188 void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel) 189 { 190 return __hists__decay_entries(hists, zap_user, zap_kernel, false); 191 } 192 193 void hists__decay_entries_threaded(struct hists *hists, 194 bool zap_user, bool zap_kernel) 195 { 196 return __hists__decay_entries(hists, zap_user, zap_kernel, true); 197 } 198 199 /* 200 * histogram, sorted on item, collects periods 201 */ 202 203 static struct hist_entry *hist_entry__new(struct hist_entry *template) 204 { 205 size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0; 206 struct hist_entry *he = malloc(sizeof(*he) + callchain_size); 207 208 if (he != NULL) { 209 *he = *template; 210 he->nr_events = 1; 211 if (he->ms.map) 212 he->ms.map->referenced = true; 213 if (symbol_conf.use_callchain) 214 callchain_init(he->callchain); 215 } 216 217 return he; 218 } 219 220 static void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) 221 { 222 if (!h->filtered) { 223 hists__calc_col_len(hists, h); 224 ++hists->nr_entries; 225 hists->stats.total_period += h->period; 226 } 227 } 228 229 static u8 symbol__parent_filter(const struct symbol *parent) 230 { 231 if (symbol_conf.exclude_other && parent == NULL) 232 return 1 << HIST_FILTER__PARENT; 233 return 0; 234 } 235 236 static struct hist_entry *add_hist_entry(struct hists *hists, 237 struct hist_entry *entry, 238 struct addr_location *al, 239 u64 period) 240 { 241 struct rb_node **p; 242 struct rb_node *parent = NULL; 243 struct hist_entry *he; 244 int cmp; 245 246 pthread_mutex_lock(&hists->lock); 247 248 p = &hists->entries_in->rb_node; 249 250 while (*p != NULL) { 251 parent = *p; 252 he = rb_entry(parent, struct hist_entry, rb_node_in); 253 254 cmp = hist_entry__cmp(entry, he); 255 256 if (!cmp) { 257 he->period += period; 258 ++he->nr_events; 259 goto out; 260 } 261 262 if (cmp < 0) 263 p = &(*p)->rb_left; 264 else 265 p = &(*p)->rb_right; 266 } 267 268 he = hist_entry__new(entry); 269 if (!he) 270 goto out_unlock; 271 272 rb_link_node(&he->rb_node_in, parent, p); 273 rb_insert_color(&he->rb_node_in, hists->entries_in); 274 out: 275 hist_entry__add_cpumode_period(he, al->cpumode, period); 276 out_unlock: 277 pthread_mutex_unlock(&hists->lock); 278 return he; 279 } 280 281 struct hist_entry *__hists__add_branch_entry(struct hists *self, 282 struct addr_location *al, 283 struct symbol *sym_parent, 284 struct branch_info *bi, 285 u64 period) 286 { 287 struct hist_entry entry = { 288 .thread = al->thread, 289 .ms = { 290 .map = bi->to.map, 291 .sym = bi->to.sym, 292 }, 293 .cpu = al->cpu, 294 .ip = bi->to.addr, 295 .level = al->level, 296 .period = period, 297 .parent = sym_parent, 298 .filtered = symbol__parent_filter(sym_parent), 299 .branch_info = bi, 300 }; 301 302 return add_hist_entry(self, &entry, al, period); 303 } 304 305 struct hist_entry *__hists__add_entry(struct hists *self, 306 struct addr_location *al, 307 struct symbol *sym_parent, u64 period) 308 { 309 struct hist_entry entry = { 310 .thread = al->thread, 311 .ms = { 312 .map = al->map, 313 .sym = al->sym, 314 }, 315 .cpu = al->cpu, 316 .ip = al->addr, 317 .level = al->level, 318 .period = period, 319 .parent = sym_parent, 320 .filtered = symbol__parent_filter(sym_parent), 321 }; 322 323 return add_hist_entry(self, &entry, al, period); 324 } 325 326 int64_t 327 hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) 328 { 329 struct sort_entry *se; 330 int64_t cmp = 0; 331 332 list_for_each_entry(se, &hist_entry__sort_list, list) { 333 cmp = se->se_cmp(left, right); 334 if (cmp) 335 break; 336 } 337 338 return cmp; 339 } 340 341 int64_t 342 hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) 343 { 344 struct sort_entry *se; 345 int64_t cmp = 0; 346 347 list_for_each_entry(se, &hist_entry__sort_list, list) { 348 int64_t (*f)(struct hist_entry *, struct hist_entry *); 349 350 f = se->se_collapse ?: se->se_cmp; 351 352 cmp = f(left, right); 353 if (cmp) 354 break; 355 } 356 357 return cmp; 358 } 359 360 void hist_entry__free(struct hist_entry *he) 361 { 362 free(he); 363 } 364 365 /* 366 * collapse the histogram 367 */ 368 369 static bool hists__collapse_insert_entry(struct hists *hists, 370 struct rb_root *root, 371 struct hist_entry *he) 372 { 373 struct rb_node **p = &root->rb_node; 374 struct rb_node *parent = NULL; 375 struct hist_entry *iter; 376 int64_t cmp; 377 378 while (*p != NULL) { 379 parent = *p; 380 iter = rb_entry(parent, struct hist_entry, rb_node_in); 381 382 cmp = hist_entry__collapse(iter, he); 383 384 if (!cmp) { 385 iter->period += he->period; 386 iter->nr_events += he->nr_events; 387 if (symbol_conf.use_callchain) { 388 callchain_cursor_reset(&hists->callchain_cursor); 389 callchain_merge(&hists->callchain_cursor, iter->callchain, 390 he->callchain); 391 } 392 hist_entry__free(he); 393 return false; 394 } 395 396 if (cmp < 0) 397 p = &(*p)->rb_left; 398 else 399 p = &(*p)->rb_right; 400 } 401 402 rb_link_node(&he->rb_node_in, parent, p); 403 rb_insert_color(&he->rb_node_in, root); 404 return true; 405 } 406 407 static struct rb_root *hists__get_rotate_entries_in(struct hists *hists) 408 { 409 struct rb_root *root; 410 411 pthread_mutex_lock(&hists->lock); 412 413 root = hists->entries_in; 414 if (++hists->entries_in > &hists->entries_in_array[1]) 415 hists->entries_in = &hists->entries_in_array[0]; 416 417 pthread_mutex_unlock(&hists->lock); 418 419 return root; 420 } 421 422 static void hists__apply_filters(struct hists *hists, struct hist_entry *he) 423 { 424 hists__filter_entry_by_dso(hists, he); 425 hists__filter_entry_by_thread(hists, he); 426 hists__filter_entry_by_symbol(hists, he); 427 } 428 429 static void __hists__collapse_resort(struct hists *hists, bool threaded) 430 { 431 struct rb_root *root; 432 struct rb_node *next; 433 struct hist_entry *n; 434 435 if (!sort__need_collapse && !threaded) 436 return; 437 438 root = hists__get_rotate_entries_in(hists); 439 next = rb_first(root); 440 441 while (next) { 442 n = rb_entry(next, struct hist_entry, rb_node_in); 443 next = rb_next(&n->rb_node_in); 444 445 rb_erase(&n->rb_node_in, root); 446 if (hists__collapse_insert_entry(hists, &hists->entries_collapsed, n)) { 447 /* 448 * If it wasn't combined with one of the entries already 449 * collapsed, we need to apply the filters that may have 450 * been set by, say, the hist_browser. 451 */ 452 hists__apply_filters(hists, n); 453 } 454 } 455 } 456 457 void hists__collapse_resort(struct hists *hists) 458 { 459 return __hists__collapse_resort(hists, false); 460 } 461 462 void hists__collapse_resort_threaded(struct hists *hists) 463 { 464 return __hists__collapse_resort(hists, true); 465 } 466 467 /* 468 * reverse the map, sort on period. 469 */ 470 471 static void __hists__insert_output_entry(struct rb_root *entries, 472 struct hist_entry *he, 473 u64 min_callchain_hits) 474 { 475 struct rb_node **p = &entries->rb_node; 476 struct rb_node *parent = NULL; 477 struct hist_entry *iter; 478 479 if (symbol_conf.use_callchain) 480 callchain_param.sort(&he->sorted_chain, he->callchain, 481 min_callchain_hits, &callchain_param); 482 483 while (*p != NULL) { 484 parent = *p; 485 iter = rb_entry(parent, struct hist_entry, rb_node); 486 487 if (he->period > iter->period) 488 p = &(*p)->rb_left; 489 else 490 p = &(*p)->rb_right; 491 } 492 493 rb_link_node(&he->rb_node, parent, p); 494 rb_insert_color(&he->rb_node, entries); 495 } 496 497 static void __hists__output_resort(struct hists *hists, bool threaded) 498 { 499 struct rb_root *root; 500 struct rb_node *next; 501 struct hist_entry *n; 502 u64 min_callchain_hits; 503 504 min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100); 505 506 if (sort__need_collapse || threaded) 507 root = &hists->entries_collapsed; 508 else 509 root = hists->entries_in; 510 511 next = rb_first(root); 512 hists->entries = RB_ROOT; 513 514 hists->nr_entries = 0; 515 hists->stats.total_period = 0; 516 hists__reset_col_len(hists); 517 518 while (next) { 519 n = rb_entry(next, struct hist_entry, rb_node_in); 520 next = rb_next(&n->rb_node_in); 521 522 __hists__insert_output_entry(&hists->entries, n, min_callchain_hits); 523 hists__inc_nr_entries(hists, n); 524 } 525 } 526 527 void hists__output_resort(struct hists *hists) 528 { 529 return __hists__output_resort(hists, false); 530 } 531 532 void hists__output_resort_threaded(struct hists *hists) 533 { 534 return __hists__output_resort(hists, true); 535 } 536 537 static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) 538 { 539 int i; 540 int ret = fprintf(fp, " "); 541 542 for (i = 0; i < left_margin; i++) 543 ret += fprintf(fp, " "); 544 545 return ret; 546 } 547 548 static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask, 549 int left_margin) 550 { 551 int i; 552 size_t ret = callchain__fprintf_left_margin(fp, left_margin); 553 554 for (i = 0; i < depth; i++) 555 if (depth_mask & (1 << i)) 556 ret += fprintf(fp, "| "); 557 else 558 ret += fprintf(fp, " "); 559 560 ret += fprintf(fp, "\n"); 561 562 return ret; 563 } 564 565 static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain, 566 int depth, int depth_mask, int period, 567 u64 total_samples, u64 hits, 568 int left_margin) 569 { 570 int i; 571 size_t ret = 0; 572 573 ret += callchain__fprintf_left_margin(fp, left_margin); 574 for (i = 0; i < depth; i++) { 575 if (depth_mask & (1 << i)) 576 ret += fprintf(fp, "|"); 577 else 578 ret += fprintf(fp, " "); 579 if (!period && i == depth - 1) { 580 double percent; 581 582 percent = hits * 100.0 / total_samples; 583 ret += percent_color_fprintf(fp, "--%2.2f%%-- ", percent); 584 } else 585 ret += fprintf(fp, "%s", " "); 586 } 587 if (chain->ms.sym) 588 ret += fprintf(fp, "%s\n", chain->ms.sym->name); 589 else 590 ret += fprintf(fp, "%p\n", (void *)(long)chain->ip); 591 592 return ret; 593 } 594 595 static struct symbol *rem_sq_bracket; 596 static struct callchain_list rem_hits; 597 598 static void init_rem_hits(void) 599 { 600 rem_sq_bracket = malloc(sizeof(*rem_sq_bracket) + 6); 601 if (!rem_sq_bracket) { 602 fprintf(stderr, "Not enough memory to display remaining hits\n"); 603 return; 604 } 605 606 strcpy(rem_sq_bracket->name, "[...]"); 607 rem_hits.ms.sym = rem_sq_bracket; 608 } 609 610 static size_t __callchain__fprintf_graph(FILE *fp, struct rb_root *root, 611 u64 total_samples, int depth, 612 int depth_mask, int left_margin) 613 { 614 struct rb_node *node, *next; 615 struct callchain_node *child; 616 struct callchain_list *chain; 617 int new_depth_mask = depth_mask; 618 u64 remaining; 619 size_t ret = 0; 620 int i; 621 uint entries_printed = 0; 622 623 remaining = total_samples; 624 625 node = rb_first(root); 626 while (node) { 627 u64 new_total; 628 u64 cumul; 629 630 child = rb_entry(node, struct callchain_node, rb_node); 631 cumul = callchain_cumul_hits(child); 632 remaining -= cumul; 633 634 /* 635 * The depth mask manages the output of pipes that show 636 * the depth. We don't want to keep the pipes of the current 637 * level for the last child of this depth. 638 * Except if we have remaining filtered hits. They will 639 * supersede the last child 640 */ 641 next = rb_next(node); 642 if (!next && (callchain_param.mode != CHAIN_GRAPH_REL || !remaining)) 643 new_depth_mask &= ~(1 << (depth - 1)); 644 645 /* 646 * But we keep the older depth mask for the line separator 647 * to keep the level link until we reach the last child 648 */ 649 ret += ipchain__fprintf_graph_line(fp, depth, depth_mask, 650 left_margin); 651 i = 0; 652 list_for_each_entry(chain, &child->val, list) { 653 ret += ipchain__fprintf_graph(fp, chain, depth, 654 new_depth_mask, i++, 655 total_samples, 656 cumul, 657 left_margin); 658 } 659 660 if (callchain_param.mode == CHAIN_GRAPH_REL) 661 new_total = child->children_hit; 662 else 663 new_total = total_samples; 664 665 ret += __callchain__fprintf_graph(fp, &child->rb_root, new_total, 666 depth + 1, 667 new_depth_mask | (1 << depth), 668 left_margin); 669 node = next; 670 if (++entries_printed == callchain_param.print_limit) 671 break; 672 } 673 674 if (callchain_param.mode == CHAIN_GRAPH_REL && 675 remaining && remaining != total_samples) { 676 677 if (!rem_sq_bracket) 678 return ret; 679 680 new_depth_mask &= ~(1 << (depth - 1)); 681 ret += ipchain__fprintf_graph(fp, &rem_hits, depth, 682 new_depth_mask, 0, total_samples, 683 remaining, left_margin); 684 } 685 686 return ret; 687 } 688 689 static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, 690 u64 total_samples, int left_margin) 691 { 692 struct callchain_node *cnode; 693 struct callchain_list *chain; 694 u32 entries_printed = 0; 695 bool printed = false; 696 struct rb_node *node; 697 int i = 0; 698 int ret; 699 700 /* 701 * If have one single callchain root, don't bother printing 702 * its percentage (100 % in fractal mode and the same percentage 703 * than the hist in graph mode). This also avoid one level of column. 704 */ 705 node = rb_first(root); 706 if (node && !rb_next(node)) { 707 cnode = rb_entry(node, struct callchain_node, rb_node); 708 list_for_each_entry(chain, &cnode->val, list) { 709 /* 710 * If we sort by symbol, the first entry is the same than 711 * the symbol. No need to print it otherwise it appears as 712 * displayed twice. 713 */ 714 if (!i++ && sort__first_dimension == SORT_SYM) 715 continue; 716 if (!printed) { 717 ret += callchain__fprintf_left_margin(fp, left_margin); 718 ret += fprintf(fp, "|\n"); 719 ret += callchain__fprintf_left_margin(fp, left_margin); 720 ret += fprintf(fp, "---"); 721 left_margin += 3; 722 printed = true; 723 } else 724 ret += callchain__fprintf_left_margin(fp, left_margin); 725 726 if (chain->ms.sym) 727 ret += fprintf(fp, " %s\n", chain->ms.sym->name); 728 else 729 ret += fprintf(fp, " %p\n", (void *)(long)chain->ip); 730 731 if (++entries_printed == callchain_param.print_limit) 732 break; 733 } 734 root = &cnode->rb_root; 735 } 736 737 return __callchain__fprintf_graph(fp, root, total_samples, 738 1, 1, left_margin); 739 } 740 741 static size_t __callchain__fprintf_flat(FILE *fp, 742 struct callchain_node *self, 743 u64 total_samples) 744 { 745 struct callchain_list *chain; 746 size_t ret = 0; 747 748 if (!self) 749 return 0; 750 751 ret += __callchain__fprintf_flat(fp, self->parent, total_samples); 752 753 754 list_for_each_entry(chain, &self->val, list) { 755 if (chain->ip >= PERF_CONTEXT_MAX) 756 continue; 757 if (chain->ms.sym) 758 ret += fprintf(fp, " %s\n", chain->ms.sym->name); 759 else 760 ret += fprintf(fp, " %p\n", 761 (void *)(long)chain->ip); 762 } 763 764 return ret; 765 } 766 767 static size_t callchain__fprintf_flat(FILE *fp, struct rb_root *self, 768 u64 total_samples) 769 { 770 size_t ret = 0; 771 u32 entries_printed = 0; 772 struct rb_node *rb_node; 773 struct callchain_node *chain; 774 775 rb_node = rb_first(self); 776 while (rb_node) { 777 double percent; 778 779 chain = rb_entry(rb_node, struct callchain_node, rb_node); 780 percent = chain->hit * 100.0 / total_samples; 781 782 ret = percent_color_fprintf(fp, " %6.2f%%\n", percent); 783 ret += __callchain__fprintf_flat(fp, chain, total_samples); 784 ret += fprintf(fp, "\n"); 785 if (++entries_printed == callchain_param.print_limit) 786 break; 787 788 rb_node = rb_next(rb_node); 789 } 790 791 return ret; 792 } 793 794 static size_t hist_entry_callchain__fprintf(struct hist_entry *he, 795 u64 total_samples, int left_margin, 796 FILE *fp) 797 { 798 switch (callchain_param.mode) { 799 case CHAIN_GRAPH_REL: 800 return callchain__fprintf_graph(fp, &he->sorted_chain, he->period, 801 left_margin); 802 break; 803 case CHAIN_GRAPH_ABS: 804 return callchain__fprintf_graph(fp, &he->sorted_chain, total_samples, 805 left_margin); 806 break; 807 case CHAIN_FLAT: 808 return callchain__fprintf_flat(fp, &he->sorted_chain, total_samples); 809 break; 810 case CHAIN_NONE: 811 break; 812 default: 813 pr_err("Bad callchain mode\n"); 814 } 815 816 return 0; 817 } 818 819 void hists__output_recalc_col_len(struct hists *hists, int max_rows) 820 { 821 struct rb_node *next = rb_first(&hists->entries); 822 struct hist_entry *n; 823 int row = 0; 824 825 hists__reset_col_len(hists); 826 827 while (next && row++ < max_rows) { 828 n = rb_entry(next, struct hist_entry, rb_node); 829 if (!n->filtered) 830 hists__calc_col_len(hists, n); 831 next = rb_next(&n->rb_node); 832 } 833 } 834 835 static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s, 836 size_t size, struct hists *pair_hists, 837 bool show_displacement, long displacement, 838 bool color, u64 total_period) 839 { 840 u64 period, total, period_sys, period_us, period_guest_sys, period_guest_us; 841 u64 nr_events; 842 const char *sep = symbol_conf.field_sep; 843 int ret; 844 845 if (symbol_conf.exclude_other && !he->parent) 846 return 0; 847 848 if (pair_hists) { 849 period = he->pair ? he->pair->period : 0; 850 nr_events = he->pair ? he->pair->nr_events : 0; 851 total = pair_hists->stats.total_period; 852 period_sys = he->pair ? he->pair->period_sys : 0; 853 period_us = he->pair ? he->pair->period_us : 0; 854 period_guest_sys = he->pair ? he->pair->period_guest_sys : 0; 855 period_guest_us = he->pair ? he->pair->period_guest_us : 0; 856 } else { 857 period = he->period; 858 nr_events = he->nr_events; 859 total = total_period; 860 period_sys = he->period_sys; 861 period_us = he->period_us; 862 period_guest_sys = he->period_guest_sys; 863 period_guest_us = he->period_guest_us; 864 } 865 866 if (total) { 867 if (color) 868 ret = percent_color_snprintf(s, size, 869 sep ? "%.2f" : " %6.2f%%", 870 (period * 100.0) / total); 871 else 872 ret = scnprintf(s, size, sep ? "%.2f" : " %6.2f%%", 873 (period * 100.0) / total); 874 if (symbol_conf.show_cpu_utilization) { 875 ret += percent_color_snprintf(s + ret, size - ret, 876 sep ? "%.2f" : " %6.2f%%", 877 (period_sys * 100.0) / total); 878 ret += percent_color_snprintf(s + ret, size - ret, 879 sep ? "%.2f" : " %6.2f%%", 880 (period_us * 100.0) / total); 881 if (perf_guest) { 882 ret += percent_color_snprintf(s + ret, 883 size - ret, 884 sep ? "%.2f" : " %6.2f%%", 885 (period_guest_sys * 100.0) / 886 total); 887 ret += percent_color_snprintf(s + ret, 888 size - ret, 889 sep ? "%.2f" : " %6.2f%%", 890 (period_guest_us * 100.0) / 891 total); 892 } 893 } 894 } else 895 ret = scnprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period); 896 897 if (symbol_conf.show_nr_samples) { 898 if (sep) 899 ret += scnprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events); 900 else 901 ret += scnprintf(s + ret, size - ret, "%11" PRIu64, nr_events); 902 } 903 904 if (symbol_conf.show_total_period) { 905 if (sep) 906 ret += scnprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period); 907 else 908 ret += scnprintf(s + ret, size - ret, " %12" PRIu64, period); 909 } 910 911 if (pair_hists) { 912 char bf[32]; 913 double old_percent = 0, new_percent = 0, diff; 914 915 if (total > 0) 916 old_percent = (period * 100.0) / total; 917 if (total_period > 0) 918 new_percent = (he->period * 100.0) / total_period; 919 920 diff = new_percent - old_percent; 921 922 if (fabs(diff) >= 0.01) 923 scnprintf(bf, sizeof(bf), "%+4.2F%%", diff); 924 else 925 scnprintf(bf, sizeof(bf), " "); 926 927 if (sep) 928 ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf); 929 else 930 ret += scnprintf(s + ret, size - ret, "%11.11s", bf); 931 932 if (show_displacement) { 933 if (displacement) 934 scnprintf(bf, sizeof(bf), "%+4ld", displacement); 935 else 936 scnprintf(bf, sizeof(bf), " "); 937 938 if (sep) 939 ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf); 940 else 941 ret += scnprintf(s + ret, size - ret, "%6.6s", bf); 942 } 943 } 944 945 return ret; 946 } 947 948 int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size, 949 struct hists *hists) 950 { 951 const char *sep = symbol_conf.field_sep; 952 struct sort_entry *se; 953 int ret = 0; 954 955 list_for_each_entry(se, &hist_entry__sort_list, list) { 956 if (se->elide) 957 continue; 958 959 ret += scnprintf(s + ret, size - ret, "%s", sep ?: " "); 960 ret += se->se_snprintf(he, s + ret, size - ret, 961 hists__col_len(hists, se->se_width_idx)); 962 } 963 964 return ret; 965 } 966 967 static int hist_entry__fprintf(struct hist_entry *he, size_t size, 968 struct hists *hists, struct hists *pair_hists, 969 bool show_displacement, long displacement, 970 u64 total_period, FILE *fp) 971 { 972 char bf[512]; 973 int ret; 974 975 if (size == 0 || size > sizeof(bf)) 976 size = sizeof(bf); 977 978 ret = hist_entry__pcnt_snprintf(he, bf, size, pair_hists, 979 show_displacement, displacement, 980 true, total_period); 981 hist_entry__snprintf(he, bf + ret, size - ret, hists); 982 return fprintf(fp, "%s\n", bf); 983 } 984 985 static size_t hist_entry__fprintf_callchain(struct hist_entry *he, 986 struct hists *hists, 987 u64 total_period, FILE *fp) 988 { 989 int left_margin = 0; 990 991 if (sort__first_dimension == SORT_COMM) { 992 struct sort_entry *se = list_first_entry(&hist_entry__sort_list, 993 typeof(*se), list); 994 left_margin = hists__col_len(hists, se->se_width_idx); 995 left_margin -= thread__comm_len(he->thread); 996 } 997 998 return hist_entry_callchain__fprintf(he, total_period, left_margin, fp); 999 } 1000 1001 size_t hists__fprintf(struct hists *hists, struct hists *pair, 1002 bool show_displacement, bool show_header, int max_rows, 1003 int max_cols, FILE *fp) 1004 { 1005 struct sort_entry *se; 1006 struct rb_node *nd; 1007 size_t ret = 0; 1008 u64 total_period; 1009 unsigned long position = 1; 1010 long displacement = 0; 1011 unsigned int width; 1012 const char *sep = symbol_conf.field_sep; 1013 const char *col_width = symbol_conf.col_width_list_str; 1014 int nr_rows = 0; 1015 1016 init_rem_hits(); 1017 1018 if (!show_header) 1019 goto print_entries; 1020 1021 fprintf(fp, "# %s", pair ? "Baseline" : "Overhead"); 1022 1023 if (symbol_conf.show_cpu_utilization) { 1024 if (sep) { 1025 ret += fprintf(fp, "%csys", *sep); 1026 ret += fprintf(fp, "%cus", *sep); 1027 if (perf_guest) { 1028 ret += fprintf(fp, "%cguest sys", *sep); 1029 ret += fprintf(fp, "%cguest us", *sep); 1030 } 1031 } else { 1032 ret += fprintf(fp, " sys "); 1033 ret += fprintf(fp, " us "); 1034 if (perf_guest) { 1035 ret += fprintf(fp, " guest sys "); 1036 ret += fprintf(fp, " guest us "); 1037 } 1038 } 1039 } 1040 1041 if (symbol_conf.show_nr_samples) { 1042 if (sep) 1043 fprintf(fp, "%cSamples", *sep); 1044 else 1045 fputs(" Samples ", fp); 1046 } 1047 1048 if (symbol_conf.show_total_period) { 1049 if (sep) 1050 ret += fprintf(fp, "%cPeriod", *sep); 1051 else 1052 ret += fprintf(fp, " Period "); 1053 } 1054 1055 if (pair) { 1056 if (sep) 1057 ret += fprintf(fp, "%cDelta", *sep); 1058 else 1059 ret += fprintf(fp, " Delta "); 1060 1061 if (show_displacement) { 1062 if (sep) 1063 ret += fprintf(fp, "%cDisplacement", *sep); 1064 else 1065 ret += fprintf(fp, " Displ"); 1066 } 1067 } 1068 1069 list_for_each_entry(se, &hist_entry__sort_list, list) { 1070 if (se->elide) 1071 continue; 1072 if (sep) { 1073 fprintf(fp, "%c%s", *sep, se->se_header); 1074 continue; 1075 } 1076 width = strlen(se->se_header); 1077 if (symbol_conf.col_width_list_str) { 1078 if (col_width) { 1079 hists__set_col_len(hists, se->se_width_idx, 1080 atoi(col_width)); 1081 col_width = strchr(col_width, ','); 1082 if (col_width) 1083 ++col_width; 1084 } 1085 } 1086 if (!hists__new_col_len(hists, se->se_width_idx, width)) 1087 width = hists__col_len(hists, se->se_width_idx); 1088 fprintf(fp, " %*s", width, se->se_header); 1089 } 1090 1091 fprintf(fp, "\n"); 1092 if (max_rows && ++nr_rows >= max_rows) 1093 goto out; 1094 1095 if (sep) 1096 goto print_entries; 1097 1098 fprintf(fp, "# ........"); 1099 if (symbol_conf.show_cpu_utilization) 1100 fprintf(fp, " ....... ......."); 1101 if (symbol_conf.show_nr_samples) 1102 fprintf(fp, " .........."); 1103 if (symbol_conf.show_total_period) 1104 fprintf(fp, " ............"); 1105 if (pair) { 1106 fprintf(fp, " .........."); 1107 if (show_displacement) 1108 fprintf(fp, " ....."); 1109 } 1110 list_for_each_entry(se, &hist_entry__sort_list, list) { 1111 unsigned int i; 1112 1113 if (se->elide) 1114 continue; 1115 1116 fprintf(fp, " "); 1117 width = hists__col_len(hists, se->se_width_idx); 1118 if (width == 0) 1119 width = strlen(se->se_header); 1120 for (i = 0; i < width; i++) 1121 fprintf(fp, "."); 1122 } 1123 1124 fprintf(fp, "\n"); 1125 if (max_rows && ++nr_rows >= max_rows) 1126 goto out; 1127 1128 fprintf(fp, "#\n"); 1129 if (max_rows && ++nr_rows >= max_rows) 1130 goto out; 1131 1132 print_entries: 1133 total_period = hists->stats.total_period; 1134 1135 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1136 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1137 1138 if (h->filtered) 1139 continue; 1140 1141 if (show_displacement) { 1142 if (h->pair != NULL) 1143 displacement = ((long)h->pair->position - 1144 (long)position); 1145 else 1146 displacement = 0; 1147 ++position; 1148 } 1149 ret += hist_entry__fprintf(h, max_cols, hists, pair, show_displacement, 1150 displacement, total_period, fp); 1151 1152 if (symbol_conf.use_callchain) 1153 ret += hist_entry__fprintf_callchain(h, hists, total_period, fp); 1154 if (max_rows && ++nr_rows >= max_rows) 1155 goto out; 1156 1157 if (h->ms.map == NULL && verbose > 1) { 1158 __map_groups__fprintf_maps(&h->thread->mg, 1159 MAP__FUNCTION, verbose, fp); 1160 fprintf(fp, "%.10s end\n", graph_dotted_line); 1161 } 1162 } 1163 out: 1164 free(rem_sq_bracket); 1165 1166 return ret; 1167 } 1168 1169 /* 1170 * See hists__fprintf to match the column widths 1171 */ 1172 unsigned int hists__sort_list_width(struct hists *hists) 1173 { 1174 struct sort_entry *se; 1175 int ret = 9; /* total % */ 1176 1177 if (symbol_conf.show_cpu_utilization) { 1178 ret += 7; /* count_sys % */ 1179 ret += 6; /* count_us % */ 1180 if (perf_guest) { 1181 ret += 13; /* count_guest_sys % */ 1182 ret += 12; /* count_guest_us % */ 1183 } 1184 } 1185 1186 if (symbol_conf.show_nr_samples) 1187 ret += 11; 1188 1189 if (symbol_conf.show_total_period) 1190 ret += 13; 1191 1192 list_for_each_entry(se, &hist_entry__sort_list, list) 1193 if (!se->elide) 1194 ret += 2 + hists__col_len(hists, se->se_width_idx); 1195 1196 if (verbose) /* Addr + origin */ 1197 ret += 3 + BITS_PER_LONG / 4; 1198 1199 return ret; 1200 } 1201 1202 static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h, 1203 enum hist_filter filter) 1204 { 1205 h->filtered &= ~(1 << filter); 1206 if (h->filtered) 1207 return; 1208 1209 ++hists->nr_entries; 1210 if (h->ms.unfolded) 1211 hists->nr_entries += h->nr_rows; 1212 h->row_offset = 0; 1213 hists->stats.total_period += h->period; 1214 hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->nr_events; 1215 1216 hists__calc_col_len(hists, h); 1217 } 1218 1219 1220 static bool hists__filter_entry_by_dso(struct hists *hists, 1221 struct hist_entry *he) 1222 { 1223 if (hists->dso_filter != NULL && 1224 (he->ms.map == NULL || he->ms.map->dso != hists->dso_filter)) { 1225 he->filtered |= (1 << HIST_FILTER__DSO); 1226 return true; 1227 } 1228 1229 return false; 1230 } 1231 1232 void hists__filter_by_dso(struct hists *hists) 1233 { 1234 struct rb_node *nd; 1235 1236 hists->nr_entries = hists->stats.total_period = 0; 1237 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1238 hists__reset_col_len(hists); 1239 1240 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1241 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1242 1243 if (symbol_conf.exclude_other && !h->parent) 1244 continue; 1245 1246 if (hists__filter_entry_by_dso(hists, h)) 1247 continue; 1248 1249 hists__remove_entry_filter(hists, h, HIST_FILTER__DSO); 1250 } 1251 } 1252 1253 static bool hists__filter_entry_by_thread(struct hists *hists, 1254 struct hist_entry *he) 1255 { 1256 if (hists->thread_filter != NULL && 1257 he->thread != hists->thread_filter) { 1258 he->filtered |= (1 << HIST_FILTER__THREAD); 1259 return true; 1260 } 1261 1262 return false; 1263 } 1264 1265 void hists__filter_by_thread(struct hists *hists) 1266 { 1267 struct rb_node *nd; 1268 1269 hists->nr_entries = hists->stats.total_period = 0; 1270 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1271 hists__reset_col_len(hists); 1272 1273 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1274 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1275 1276 if (hists__filter_entry_by_thread(hists, h)) 1277 continue; 1278 1279 hists__remove_entry_filter(hists, h, HIST_FILTER__THREAD); 1280 } 1281 } 1282 1283 static bool hists__filter_entry_by_symbol(struct hists *hists, 1284 struct hist_entry *he) 1285 { 1286 if (hists->symbol_filter_str != NULL && 1287 (!he->ms.sym || strstr(he->ms.sym->name, 1288 hists->symbol_filter_str) == NULL)) { 1289 he->filtered |= (1 << HIST_FILTER__SYMBOL); 1290 return true; 1291 } 1292 1293 return false; 1294 } 1295 1296 void hists__filter_by_symbol(struct hists *hists) 1297 { 1298 struct rb_node *nd; 1299 1300 hists->nr_entries = hists->stats.total_period = 0; 1301 hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; 1302 hists__reset_col_len(hists); 1303 1304 for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { 1305 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); 1306 1307 if (hists__filter_entry_by_symbol(hists, h)) 1308 continue; 1309 1310 hists__remove_entry_filter(hists, h, HIST_FILTER__SYMBOL); 1311 } 1312 } 1313 1314 int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip) 1315 { 1316 return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip); 1317 } 1318 1319 int hist_entry__annotate(struct hist_entry *he, size_t privsize) 1320 { 1321 return symbol__annotate(he->ms.sym, he->ms.map, privsize); 1322 } 1323 1324 void hists__inc_nr_events(struct hists *hists, u32 type) 1325 { 1326 ++hists->stats.nr_events[0]; 1327 ++hists->stats.nr_events[type]; 1328 } 1329 1330 size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) 1331 { 1332 int i; 1333 size_t ret = 0; 1334 1335 for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { 1336 const char *name; 1337 1338 if (hists->stats.nr_events[i] == 0) 1339 continue; 1340 1341 name = perf_event__name(i); 1342 if (!strcmp(name, "UNKNOWN")) 1343 continue; 1344 1345 ret += fprintf(fp, "%16s events: %10d\n", name, 1346 hists->stats.nr_events[i]); 1347 } 1348 1349 return ret; 1350 } 1351