diff options
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/ui/browsers/hists.c | 203 |
1 files changed, 80 insertions, 123 deletions
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 519353d9f5fb..d4cef68176da 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -477,20 +477,37 @@ static char *callchain_list__sym_name(struct callchain_list *cl, | |||
477 | return bf; | 477 | return bf; |
478 | } | 478 | } |
479 | 479 | ||
480 | struct callchain_print_arg { | ||
481 | /* for hists browser */ | ||
482 | off_t row_offset; | ||
483 | bool is_current_entry; | ||
484 | |||
485 | /* for file dump */ | ||
486 | FILE *fp; | ||
487 | int printed; | ||
488 | }; | ||
489 | |||
490 | typedef void (*print_callchain_entry_fn)(struct hist_browser *browser, | ||
491 | struct callchain_list *chain, | ||
492 | const char *str, int offset, | ||
493 | unsigned short row, | ||
494 | struct callchain_print_arg *arg); | ||
495 | |||
480 | static void hist_browser__show_callchain_entry(struct hist_browser *browser, | 496 | static void hist_browser__show_callchain_entry(struct hist_browser *browser, |
481 | struct callchain_list *chain, | 497 | struct callchain_list *chain, |
482 | unsigned short row, int offset, | 498 | const char *str, int offset, |
483 | char folded_sign, const char *str, | 499 | unsigned short row, |
484 | bool *is_current_entry) | 500 | struct callchain_print_arg *arg) |
485 | { | 501 | { |
486 | int color, width; | 502 | int color, width; |
503 | char folded_sign = callchain_list__folded(chain); | ||
487 | 504 | ||
488 | color = HE_COLORSET_NORMAL; | 505 | color = HE_COLORSET_NORMAL; |
489 | width = browser->b.width - (offset + 2); | 506 | width = browser->b.width - (offset + 2); |
490 | if (ui_browser__is_current_entry(&browser->b, row)) { | 507 | if (ui_browser__is_current_entry(&browser->b, row)) { |
491 | browser->selection = &chain->ms; | 508 | browser->selection = &chain->ms; |
492 | color = HE_COLORSET_SELECTED; | 509 | color = HE_COLORSET_SELECTED; |
493 | *is_current_entry = true; | 510 | arg->is_current_entry = true; |
494 | } | 511 | } |
495 | 512 | ||
496 | ui_browser__set_color(&browser->b, color); | 513 | ui_browser__set_color(&browser->b, color); |
@@ -500,12 +517,41 @@ static void hist_browser__show_callchain_entry(struct hist_browser *browser, | |||
500 | slsmg_write_nstring(str, width); | 517 | slsmg_write_nstring(str, width); |
501 | } | 518 | } |
502 | 519 | ||
520 | static void hist_browser__fprintf_callchain_entry(struct hist_browser *b __maybe_unused, | ||
521 | struct callchain_list *chain, | ||
522 | const char *str, int offset, | ||
523 | unsigned short row __maybe_unused, | ||
524 | struct callchain_print_arg *arg) | ||
525 | { | ||
526 | char folded_sign = callchain_list__folded(chain); | ||
527 | |||
528 | arg->printed += fprintf(arg->fp, "%*s%c %s\n", offset, " ", | ||
529 | folded_sign, str); | ||
530 | } | ||
531 | |||
532 | typedef bool (*check_output_full_fn)(struct hist_browser *browser, | ||
533 | unsigned short row); | ||
534 | |||
535 | static bool hist_browser__check_output_full(struct hist_browser *browser, | ||
536 | unsigned short row) | ||
537 | { | ||
538 | return browser->b.rows == row; | ||
539 | } | ||
540 | |||
541 | static bool hist_browser__check_dump_full(struct hist_browser *browser __maybe_unused, | ||
542 | unsigned short row __maybe_unused) | ||
543 | { | ||
544 | return false; | ||
545 | } | ||
546 | |||
503 | #define LEVEL_OFFSET_STEP 3 | 547 | #define LEVEL_OFFSET_STEP 3 |
504 | 548 | ||
505 | static int hist_browser__show_callchain(struct hist_browser *browser, | 549 | static int hist_browser__show_callchain(struct hist_browser *browser, |
506 | struct rb_root *root, int level, | 550 | struct rb_root *root, int level, |
507 | unsigned short row, off_t *row_offset, | 551 | unsigned short row, u64 total, |
508 | u64 total, bool *is_current_entry) | 552 | print_callchain_entry_fn print, |
553 | struct callchain_print_arg *arg, | ||
554 | check_output_full_fn is_output_full) | ||
509 | { | 555 | { |
510 | struct rb_node *node; | 556 | struct rb_node *node; |
511 | int first_row = row, offset = level * LEVEL_OFFSET_STEP; | 557 | int first_row = row, offset = level * LEVEL_OFFSET_STEP; |
@@ -532,8 +578,8 @@ static int hist_browser__show_callchain(struct hist_browser *browser, | |||
532 | extra_offset = LEVEL_OFFSET_STEP; | 578 | extra_offset = LEVEL_OFFSET_STEP; |
533 | 579 | ||
534 | folded_sign = callchain_list__folded(chain); | 580 | folded_sign = callchain_list__folded(chain); |
535 | if (*row_offset != 0) { | 581 | if (arg->row_offset != 0) { |
536 | --*row_offset; | 582 | arg->row_offset--; |
537 | goto do_next; | 583 | goto do_next; |
538 | } | 584 | } |
539 | 585 | ||
@@ -550,13 +596,11 @@ static int hist_browser__show_callchain(struct hist_browser *browser, | |||
550 | str = alloc_str; | 596 | str = alloc_str; |
551 | } | 597 | } |
552 | 598 | ||
553 | hist_browser__show_callchain_entry(browser, chain, row, | 599 | print(browser, chain, str, offset + extra_offset, row, arg); |
554 | offset + extra_offset, | 600 | |
555 | folded_sign, str, | ||
556 | is_current_entry); | ||
557 | free(alloc_str); | 601 | free(alloc_str); |
558 | 602 | ||
559 | if (++row == browser->b.rows) | 603 | if (is_output_full(browser, ++row)) |
560 | goto out; | 604 | goto out; |
561 | do_next: | 605 | do_next: |
562 | if (folded_sign == '+') | 606 | if (folded_sign == '+') |
@@ -572,12 +616,10 @@ do_next: | |||
572 | new_total = total; | 616 | new_total = total; |
573 | 617 | ||
574 | row += hist_browser__show_callchain(browser, &child->rb_root, | 618 | row += hist_browser__show_callchain(browser, &child->rb_root, |
575 | new_level, | 619 | new_level, row, new_total, |
576 | row, row_offset, | 620 | print, arg, is_output_full); |
577 | new_total, | ||
578 | is_current_entry); | ||
579 | } | 621 | } |
580 | if (row == browser->b.rows) | 622 | if (is_output_full(browser, row)) |
581 | break; | 623 | break; |
582 | node = next; | 624 | node = next; |
583 | } | 625 | } |
@@ -757,16 +799,20 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
757 | 799 | ||
758 | if (folded_sign == '-' && row != browser->b.rows) { | 800 | if (folded_sign == '-' && row != browser->b.rows) { |
759 | u64 total = hists__total_period(entry->hists); | 801 | u64 total = hists__total_period(entry->hists); |
802 | struct callchain_print_arg arg = { | ||
803 | .row_offset = row_offset, | ||
804 | .is_current_entry = current_entry, | ||
805 | }; | ||
760 | 806 | ||
761 | if (symbol_conf.cumulate_callchain) | 807 | if (symbol_conf.cumulate_callchain) |
762 | total = entry->stat_acc->period; | 808 | total = entry->stat_acc->period; |
763 | 809 | ||
764 | printed += hist_browser__show_callchain(browser, | 810 | printed += hist_browser__show_callchain(browser, |
765 | &entry->sorted_chain, | 811 | &entry->sorted_chain, 1, row, total, |
766 | 1, row, &row_offset, | 812 | hist_browser__show_callchain_entry, &arg, |
767 | total, ¤t_entry); | 813 | hist_browser__check_output_full); |
768 | 814 | ||
769 | if (current_entry) | 815 | if (arg.is_current_entry) |
770 | browser->he_selection = entry; | 816 | browser->he_selection = entry; |
771 | } | 817 | } |
772 | 818 | ||
@@ -1022,110 +1068,21 @@ do_offset: | |||
1022 | } | 1068 | } |
1023 | } | 1069 | } |
1024 | 1070 | ||
1025 | static int hist_browser__fprintf_callchain_node_rb_tree(struct hist_browser *browser, | ||
1026 | struct callchain_node *chain_node, | ||
1027 | u64 total, int level, | ||
1028 | FILE *fp) | ||
1029 | { | ||
1030 | struct rb_node *node; | ||
1031 | int offset = level * LEVEL_OFFSET_STEP; | ||
1032 | u64 new_total; | ||
1033 | int printed = 0; | ||
1034 | |||
1035 | if (callchain_param.mode == CHAIN_GRAPH_REL) | ||
1036 | new_total = chain_node->children_hit; | ||
1037 | else | ||
1038 | new_total = total; | ||
1039 | |||
1040 | node = rb_first(&chain_node->rb_root); | ||
1041 | while (node) { | ||
1042 | struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node); | ||
1043 | struct rb_node *next = rb_next(node); | ||
1044 | u64 cumul = callchain_cumul_hits(child); | ||
1045 | struct callchain_list *chain; | ||
1046 | char folded_sign = ' '; | ||
1047 | int first = true; | ||
1048 | int extra_offset = 0; | ||
1049 | |||
1050 | list_for_each_entry(chain, &child->val, list) { | ||
1051 | char bf[1024], *alloc_str; | ||
1052 | const char *str; | ||
1053 | bool was_first = first; | ||
1054 | |||
1055 | if (first) | ||
1056 | first = false; | ||
1057 | else | ||
1058 | extra_offset = LEVEL_OFFSET_STEP; | ||
1059 | |||
1060 | folded_sign = callchain_list__folded(chain); | ||
1061 | |||
1062 | alloc_str = NULL; | ||
1063 | str = callchain_list__sym_name(chain, bf, sizeof(bf), | ||
1064 | browser->show_dso); | ||
1065 | if (was_first) { | ||
1066 | double percent = cumul * 100.0 / new_total; | ||
1067 | |||
1068 | if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0) | ||
1069 | str = "Not enough memory!"; | ||
1070 | else | ||
1071 | str = alloc_str; | ||
1072 | } | ||
1073 | |||
1074 | printed += fprintf(fp, "%*s%c %s\n", offset + extra_offset, " ", folded_sign, str); | ||
1075 | free(alloc_str); | ||
1076 | if (folded_sign == '+') | ||
1077 | break; | ||
1078 | } | ||
1079 | |||
1080 | if (folded_sign == '-') { | ||
1081 | const int new_level = level + (extra_offset ? 2 : 1); | ||
1082 | printed += hist_browser__fprintf_callchain_node_rb_tree(browser, child, new_total, | ||
1083 | new_level, fp); | ||
1084 | } | ||
1085 | |||
1086 | node = next; | ||
1087 | } | ||
1088 | |||
1089 | return printed; | ||
1090 | } | ||
1091 | |||
1092 | static int hist_browser__fprintf_callchain_node(struct hist_browser *browser, | ||
1093 | struct callchain_node *node, | ||
1094 | int level, FILE *fp) | ||
1095 | { | ||
1096 | struct callchain_list *chain; | ||
1097 | int offset = level * LEVEL_OFFSET_STEP; | ||
1098 | char folded_sign = ' '; | ||
1099 | int printed = 0; | ||
1100 | |||
1101 | list_for_each_entry(chain, &node->val, list) { | ||
1102 | char bf[1024], *s; | ||
1103 | |||
1104 | folded_sign = callchain_list__folded(chain); | ||
1105 | s = callchain_list__sym_name(chain, bf, sizeof(bf), browser->show_dso); | ||
1106 | printed += fprintf(fp, "%*s%c %s\n", offset, " ", folded_sign, s); | ||
1107 | } | ||
1108 | |||
1109 | if (folded_sign == '-') | ||
1110 | printed += hist_browser__fprintf_callchain_node_rb_tree(browser, node, | ||
1111 | browser->hists->stats.total_period, | ||
1112 | level + 1, fp); | ||
1113 | return printed; | ||
1114 | } | ||
1115 | |||
1116 | static int hist_browser__fprintf_callchain(struct hist_browser *browser, | 1071 | static int hist_browser__fprintf_callchain(struct hist_browser *browser, |
1117 | struct rb_root *chain, int level, FILE *fp) | 1072 | struct hist_entry *he, FILE *fp) |
1118 | { | 1073 | { |
1119 | struct rb_node *nd; | 1074 | u64 total = hists__total_period(he->hists); |
1120 | int printed = 0; | 1075 | struct callchain_print_arg arg = { |
1121 | 1076 | .fp = fp, | |
1122 | for (nd = rb_first(chain); nd; nd = rb_next(nd)) { | 1077 | }; |
1123 | struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node); | ||
1124 | 1078 | ||
1125 | printed += hist_browser__fprintf_callchain_node(browser, node, level, fp); | 1079 | if (symbol_conf.cumulate_callchain) |
1126 | } | 1080 | total = he->stat_acc->period; |
1127 | 1081 | ||
1128 | return printed; | 1082 | hist_browser__show_callchain(browser, &he->sorted_chain, 1, 0, total, |
1083 | hist_browser__fprintf_callchain_entry, &arg, | ||
1084 | hist_browser__check_dump_full); | ||
1085 | return arg.printed; | ||
1129 | } | 1086 | } |
1130 | 1087 | ||
1131 | static int hist_browser__fprintf_entry(struct hist_browser *browser, | 1088 | static int hist_browser__fprintf_entry(struct hist_browser *browser, |
@@ -1164,7 +1121,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, | |||
1164 | printed += fprintf(fp, "%s\n", rtrim(s)); | 1121 | printed += fprintf(fp, "%s\n", rtrim(s)); |
1165 | 1122 | ||
1166 | if (folded_sign == '-') | 1123 | if (folded_sign == '-') |
1167 | printed += hist_browser__fprintf_callchain(browser, &he->sorted_chain, 1, fp); | 1124 | printed += hist_browser__fprintf_callchain(browser, he, fp); |
1168 | 1125 | ||
1169 | return printed; | 1126 | return printed; |
1170 | } | 1127 | } |