diff options
Diffstat (limited to 'tools/perf/ui')
-rw-r--r-- | tools/perf/ui/browser.c | 6 | ||||
-rw-r--r-- | tools/perf/ui/browsers/annotate.c | 33 | ||||
-rw-r--r-- | tools/perf/ui/browsers/hists.c | 341 | ||||
-rw-r--r-- | tools/perf/ui/gtk/annotate.c | 229 | ||||
-rw-r--r-- | tools/perf/ui/gtk/browser.c | 235 | ||||
-rw-r--r-- | tools/perf/ui/gtk/gtk.h | 10 | ||||
-rw-r--r-- | tools/perf/ui/gtk/helpline.c | 23 | ||||
-rw-r--r-- | tools/perf/ui/gtk/hists.c | 312 | ||||
-rw-r--r-- | tools/perf/ui/helpline.c | 12 | ||||
-rw-r--r-- | tools/perf/ui/helpline.h | 22 | ||||
-rw-r--r-- | tools/perf/ui/hist.c | 481 | ||||
-rw-r--r-- | tools/perf/ui/keysyms.h | 1 | ||||
-rw-r--r-- | tools/perf/ui/setup.c | 3 | ||||
-rw-r--r-- | tools/perf/ui/stdio/hist.c | 25 | ||||
-rw-r--r-- | tools/perf/ui/tui/helpline.c | 29 | ||||
-rw-r--r-- | tools/perf/ui/util.c | 1 |
16 files changed, 1165 insertions, 598 deletions
diff --git a/tools/perf/ui/browser.c b/tools/perf/ui/browser.c index 4aeb7d5df939..809ea4632a34 100644 --- a/tools/perf/ui/browser.c +++ b/tools/perf/ui/browser.c | |||
@@ -273,6 +273,8 @@ void ui_browser__hide(struct ui_browser *browser __maybe_unused) | |||
273 | { | 273 | { |
274 | pthread_mutex_lock(&ui__lock); | 274 | pthread_mutex_lock(&ui__lock); |
275 | ui_helpline__pop(); | 275 | ui_helpline__pop(); |
276 | free(browser->helpline); | ||
277 | browser->helpline = NULL; | ||
276 | pthread_mutex_unlock(&ui__lock); | 278 | pthread_mutex_unlock(&ui__lock); |
277 | } | 279 | } |
278 | 280 | ||
@@ -471,7 +473,7 @@ unsigned int ui_browser__list_head_refresh(struct ui_browser *browser) | |||
471 | return row; | 473 | return row; |
472 | } | 474 | } |
473 | 475 | ||
474 | static struct ui_browser__colorset { | 476 | static struct ui_browser_colorset { |
475 | const char *name, *fg, *bg; | 477 | const char *name, *fg, *bg; |
476 | int colorset; | 478 | int colorset; |
477 | } ui_browser__colorsets[] = { | 479 | } ui_browser__colorsets[] = { |
@@ -706,7 +708,7 @@ void ui_browser__init(void) | |||
706 | perf_config(ui_browser__color_config, NULL); | 708 | perf_config(ui_browser__color_config, NULL); |
707 | 709 | ||
708 | while (ui_browser__colorsets[i].name) { | 710 | while (ui_browser__colorsets[i].name) { |
709 | struct ui_browser__colorset *c = &ui_browser__colorsets[i++]; | 711 | struct ui_browser_colorset *c = &ui_browser__colorsets[i++]; |
710 | sltt_set_color(c->colorset, c->name, c->fg, c->bg); | 712 | sltt_set_color(c->colorset, c->name, c->fg, c->bg); |
711 | } | 713 | } |
712 | 714 | ||
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c index 5dab3ca96980..7dca1555c610 100644 --- a/tools/perf/ui/browsers/annotate.c +++ b/tools/perf/ui/browsers/annotate.c | |||
@@ -182,6 +182,16 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int | |||
182 | ab->selection = dl; | 182 | ab->selection = dl; |
183 | } | 183 | } |
184 | 184 | ||
185 | static bool disasm_line__is_valid_jump(struct disasm_line *dl, struct symbol *sym) | ||
186 | { | ||
187 | if (!dl || !dl->ins || !ins__is_jump(dl->ins) | ||
188 | || !disasm_line__has_offset(dl) | ||
189 | || dl->ops.target.offset >= symbol__size(sym)) | ||
190 | return false; | ||
191 | |||
192 | return true; | ||
193 | } | ||
194 | |||
185 | static void annotate_browser__draw_current_jump(struct ui_browser *browser) | 195 | static void annotate_browser__draw_current_jump(struct ui_browser *browser) |
186 | { | 196 | { |
187 | struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); | 197 | struct annotate_browser *ab = container_of(browser, struct annotate_browser, b); |
@@ -195,8 +205,7 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser) | |||
195 | if (strstr(sym->name, "@plt")) | 205 | if (strstr(sym->name, "@plt")) |
196 | return; | 206 | return; |
197 | 207 | ||
198 | if (!cursor || !cursor->ins || !ins__is_jump(cursor->ins) || | 208 | if (!disasm_line__is_valid_jump(cursor, sym)) |
199 | !disasm_line__has_offset(cursor)) | ||
200 | return; | 209 | return; |
201 | 210 | ||
202 | target = ab->offsets[cursor->ops.target.offset]; | 211 | target = ab->offsets[cursor->ops.target.offset]; |
@@ -788,17 +797,9 @@ static void annotate_browser__mark_jump_targets(struct annotate_browser *browser | |||
788 | struct disasm_line *dl = browser->offsets[offset], *dlt; | 797 | struct disasm_line *dl = browser->offsets[offset], *dlt; |
789 | struct browser_disasm_line *bdlt; | 798 | struct browser_disasm_line *bdlt; |
790 | 799 | ||
791 | if (!dl || !dl->ins || !ins__is_jump(dl->ins) || | 800 | if (!disasm_line__is_valid_jump(dl, sym)) |
792 | !disasm_line__has_offset(dl)) | ||
793 | continue; | 801 | continue; |
794 | 802 | ||
795 | if (dl->ops.target.offset >= size) { | ||
796 | ui__error("jump to after symbol!\n" | ||
797 | "size: %zx, jump target: %" PRIx64, | ||
798 | size, dl->ops.target.offset); | ||
799 | continue; | ||
800 | } | ||
801 | |||
802 | dlt = browser->offsets[dl->ops.target.offset]; | 803 | dlt = browser->offsets[dl->ops.target.offset]; |
803 | /* | 804 | /* |
804 | * FIXME: Oops, no jump target? Buggy disassembler? Or do we | 805 | * FIXME: Oops, no jump target? Buggy disassembler? Or do we |
@@ -921,11 +922,11 @@ out_free_offsets: | |||
921 | 922 | ||
922 | #define ANNOTATE_CFG(n) \ | 923 | #define ANNOTATE_CFG(n) \ |
923 | { .name = #n, .value = &annotate_browser__opts.n, } | 924 | { .name = #n, .value = &annotate_browser__opts.n, } |
924 | 925 | ||
925 | /* | 926 | /* |
926 | * Keep the entries sorted, they are bsearch'ed | 927 | * Keep the entries sorted, they are bsearch'ed |
927 | */ | 928 | */ |
928 | static struct annotate__config { | 929 | static struct annotate_config { |
929 | const char *name; | 930 | const char *name; |
930 | bool *value; | 931 | bool *value; |
931 | } annotate__configs[] = { | 932 | } annotate__configs[] = { |
@@ -939,7 +940,7 @@ static struct annotate__config { | |||
939 | 940 | ||
940 | static int annotate_config__cmp(const void *name, const void *cfgp) | 941 | static int annotate_config__cmp(const void *name, const void *cfgp) |
941 | { | 942 | { |
942 | const struct annotate__config *cfg = cfgp; | 943 | const struct annotate_config *cfg = cfgp; |
943 | 944 | ||
944 | return strcmp(name, cfg->name); | 945 | return strcmp(name, cfg->name); |
945 | } | 946 | } |
@@ -947,7 +948,7 @@ static int annotate_config__cmp(const void *name, const void *cfgp) | |||
947 | static int annotate__config(const char *var, const char *value, | 948 | static int annotate__config(const char *var, const char *value, |
948 | void *data __maybe_unused) | 949 | void *data __maybe_unused) |
949 | { | 950 | { |
950 | struct annotate__config *cfg; | 951 | struct annotate_config *cfg; |
951 | const char *name; | 952 | const char *name; |
952 | 953 | ||
953 | if (prefixcmp(var, "annotate.") != 0) | 954 | if (prefixcmp(var, "annotate.") != 0) |
@@ -955,7 +956,7 @@ static int annotate__config(const char *var, const char *value, | |||
955 | 956 | ||
956 | name = var + 9; | 957 | name = var + 9; |
957 | cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs), | 958 | cfg = bsearch(name, annotate__configs, ARRAY_SIZE(annotate__configs), |
958 | sizeof(struct annotate__config), annotate_config__cmp); | 959 | sizeof(struct annotate_config), annotate_config__cmp); |
959 | 960 | ||
960 | if (cfg == NULL) | 961 | if (cfg == NULL) |
961 | return -1; | 962 | return -1; |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index ccc4bd161420..aa22704047d6 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
@@ -567,26 +567,128 @@ static int hist_browser__show_callchain(struct hist_browser *browser, | |||
567 | return row - first_row; | 567 | return row - first_row; |
568 | } | 568 | } |
569 | 569 | ||
570 | #define HPP__COLOR_FN(_name, _field) \ | 570 | struct hpp_arg { |
571 | static int hist_browser__hpp_color_ ## _name(struct perf_hpp *hpp, \ | 571 | struct ui_browser *b; |
572 | struct hist_entry *he) \ | 572 | char folded_sign; |
573 | bool current_entry; | ||
574 | }; | ||
575 | |||
576 | static int __hpp__color_callchain(struct hpp_arg *arg) | ||
577 | { | ||
578 | if (!symbol_conf.use_callchain) | ||
579 | return 0; | ||
580 | |||
581 | slsmg_printf("%c ", arg->folded_sign); | ||
582 | return 2; | ||
583 | } | ||
584 | |||
585 | static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he, | ||
586 | u64 (*get_field)(struct hist_entry *), | ||
587 | int (*callchain_cb)(struct hpp_arg *)) | ||
588 | { | ||
589 | int ret = 0; | ||
590 | double percent = 0.0; | ||
591 | struct hists *hists = he->hists; | ||
592 | struct hpp_arg *arg = hpp->ptr; | ||
593 | |||
594 | if (hists->stats.total_period) | ||
595 | percent = 100.0 * get_field(he) / hists->stats.total_period; | ||
596 | |||
597 | ui_browser__set_percent_color(arg->b, percent, arg->current_entry); | ||
598 | |||
599 | if (callchain_cb) | ||
600 | ret += callchain_cb(arg); | ||
601 | |||
602 | ret += scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); | ||
603 | slsmg_printf("%s", hpp->buf); | ||
604 | |||
605 | if (symbol_conf.event_group) { | ||
606 | int prev_idx, idx_delta; | ||
607 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
608 | struct hist_entry *pair; | ||
609 | int nr_members = evsel->nr_members; | ||
610 | |||
611 | if (nr_members <= 1) | ||
612 | goto out; | ||
613 | |||
614 | prev_idx = perf_evsel__group_idx(evsel); | ||
615 | |||
616 | list_for_each_entry(pair, &he->pairs.head, pairs.node) { | ||
617 | u64 period = get_field(pair); | ||
618 | u64 total = pair->hists->stats.total_period; | ||
619 | |||
620 | if (!total) | ||
621 | continue; | ||
622 | |||
623 | evsel = hists_to_evsel(pair->hists); | ||
624 | idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1; | ||
625 | |||
626 | while (idx_delta--) { | ||
627 | /* | ||
628 | * zero-fill group members in the middle which | ||
629 | * have no sample | ||
630 | */ | ||
631 | ui_browser__set_percent_color(arg->b, 0.0, | ||
632 | arg->current_entry); | ||
633 | ret += scnprintf(hpp->buf, hpp->size, | ||
634 | " %6.2f%%", 0.0); | ||
635 | slsmg_printf("%s", hpp->buf); | ||
636 | } | ||
637 | |||
638 | percent = 100.0 * period / total; | ||
639 | ui_browser__set_percent_color(arg->b, percent, | ||
640 | arg->current_entry); | ||
641 | ret += scnprintf(hpp->buf, hpp->size, | ||
642 | " %6.2f%%", percent); | ||
643 | slsmg_printf("%s", hpp->buf); | ||
644 | |||
645 | prev_idx = perf_evsel__group_idx(evsel); | ||
646 | } | ||
647 | |||
648 | idx_delta = nr_members - prev_idx - 1; | ||
649 | |||
650 | while (idx_delta--) { | ||
651 | /* | ||
652 | * zero-fill group members at last which have no sample | ||
653 | */ | ||
654 | ui_browser__set_percent_color(arg->b, 0.0, | ||
655 | arg->current_entry); | ||
656 | ret += scnprintf(hpp->buf, hpp->size, | ||
657 | " %6.2f%%", 0.0); | ||
658 | slsmg_printf("%s", hpp->buf); | ||
659 | } | ||
660 | } | ||
661 | out: | ||
662 | if (!arg->current_entry || !arg->b->navkeypressed) | ||
663 | ui_browser__set_color(arg->b, HE_COLORSET_NORMAL); | ||
664 | |||
665 | return ret; | ||
666 | } | ||
667 | |||
668 | #define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \ | ||
669 | static u64 __hpp_get_##_field(struct hist_entry *he) \ | ||
670 | { \ | ||
671 | return he->stat._field; \ | ||
672 | } \ | ||
673 | \ | ||
674 | static int hist_browser__hpp_color_##_type(struct perf_hpp *hpp, \ | ||
675 | struct hist_entry *he) \ | ||
573 | { \ | 676 | { \ |
574 | struct hists *hists = he->hists; \ | 677 | return __hpp__color_fmt(hpp, he, __hpp_get_##_field, _cb); \ |
575 | double percent = 100.0 * he->stat._field / hists->stats.total_period; \ | ||
576 | *(double *)hpp->ptr = percent; \ | ||
577 | return scnprintf(hpp->buf, hpp->size, "%6.2f%%", percent); \ | ||
578 | } | 678 | } |
579 | 679 | ||
580 | HPP__COLOR_FN(overhead, period) | 680 | __HPP_COLOR_PERCENT_FN(overhead, period, __hpp__color_callchain) |
581 | HPP__COLOR_FN(overhead_sys, period_sys) | 681 | __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, NULL) |
582 | HPP__COLOR_FN(overhead_us, period_us) | 682 | __HPP_COLOR_PERCENT_FN(overhead_us, period_us, NULL) |
583 | HPP__COLOR_FN(overhead_guest_sys, period_guest_sys) | 683 | __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, NULL) |
584 | HPP__COLOR_FN(overhead_guest_us, period_guest_us) | 684 | __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, NULL) |
585 | 685 | ||
586 | #undef HPP__COLOR_FN | 686 | #undef __HPP_COLOR_PERCENT_FN |
587 | 687 | ||
588 | void hist_browser__init_hpp(void) | 688 | void hist_browser__init_hpp(void) |
589 | { | 689 | { |
690 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
691 | |||
590 | perf_hpp__init(); | 692 | perf_hpp__init(); |
591 | 693 | ||
592 | perf_hpp__format[PERF_HPP__OVERHEAD].color = | 694 | perf_hpp__format[PERF_HPP__OVERHEAD].color = |
@@ -606,13 +708,13 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
606 | unsigned short row) | 708 | unsigned short row) |
607 | { | 709 | { |
608 | char s[256]; | 710 | char s[256]; |
609 | double percent; | 711 | int printed = 0; |
610 | int i, printed = 0; | ||
611 | int width = browser->b.width; | 712 | int width = browser->b.width; |
612 | char folded_sign = ' '; | 713 | char folded_sign = ' '; |
613 | bool current_entry = ui_browser__is_current_entry(&browser->b, row); | 714 | bool current_entry = ui_browser__is_current_entry(&browser->b, row); |
614 | off_t row_offset = entry->row_offset; | 715 | off_t row_offset = entry->row_offset; |
615 | bool first = true; | 716 | bool first = true; |
717 | struct perf_hpp_fmt *fmt; | ||
616 | 718 | ||
617 | if (current_entry) { | 719 | if (current_entry) { |
618 | browser->he_selection = entry; | 720 | browser->he_selection = entry; |
@@ -625,41 +727,30 @@ static int hist_browser__show_entry(struct hist_browser *browser, | |||
625 | } | 727 | } |
626 | 728 | ||
627 | if (row_offset == 0) { | 729 | if (row_offset == 0) { |
730 | struct hpp_arg arg = { | ||
731 | .b = &browser->b, | ||
732 | .folded_sign = folded_sign, | ||
733 | .current_entry = current_entry, | ||
734 | }; | ||
628 | struct perf_hpp hpp = { | 735 | struct perf_hpp hpp = { |
629 | .buf = s, | 736 | .buf = s, |
630 | .size = sizeof(s), | 737 | .size = sizeof(s), |
738 | .ptr = &arg, | ||
631 | }; | 739 | }; |
632 | 740 | ||
633 | ui_browser__gotorc(&browser->b, row, 0); | 741 | ui_browser__gotorc(&browser->b, row, 0); |
634 | 742 | ||
635 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | 743 | perf_hpp__for_each_format(fmt) { |
636 | if (!perf_hpp__format[i].cond) | ||
637 | continue; | ||
638 | |||
639 | if (!first) { | 744 | if (!first) { |
640 | slsmg_printf(" "); | 745 | slsmg_printf(" "); |
641 | width -= 2; | 746 | width -= 2; |
642 | } | 747 | } |
643 | first = false; | 748 | first = false; |
644 | 749 | ||
645 | if (perf_hpp__format[i].color) { | 750 | if (fmt->color) { |
646 | hpp.ptr = &percent; | 751 | width -= fmt->color(&hpp, entry); |
647 | /* It will set percent for us. See HPP__COLOR_FN above. */ | ||
648 | width -= perf_hpp__format[i].color(&hpp, entry); | ||
649 | |||
650 | ui_browser__set_percent_color(&browser->b, percent, current_entry); | ||
651 | |||
652 | if (i == PERF_HPP__OVERHEAD && symbol_conf.use_callchain) { | ||
653 | slsmg_printf("%c ", folded_sign); | ||
654 | width -= 2; | ||
655 | } | ||
656 | |||
657 | slsmg_printf("%s", s); | ||
658 | |||
659 | if (!current_entry || !browser->b.navkeypressed) | ||
660 | ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL); | ||
661 | } else { | 752 | } else { |
662 | width -= perf_hpp__format[i].entry(&hpp, entry); | 753 | width -= fmt->entry(&hpp, entry); |
663 | slsmg_printf("%s", s); | 754 | slsmg_printf("%s", s); |
664 | } | 755 | } |
665 | } | 756 | } |
@@ -1098,6 +1189,21 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size, | |||
1098 | const struct thread *thread = hists->thread_filter; | 1189 | const struct thread *thread = hists->thread_filter; |
1099 | unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; | 1190 | unsigned long nr_samples = hists->stats.nr_events[PERF_RECORD_SAMPLE]; |
1100 | u64 nr_events = hists->stats.total_period; | 1191 | u64 nr_events = hists->stats.total_period; |
1192 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
1193 | char buf[512]; | ||
1194 | size_t buflen = sizeof(buf); | ||
1195 | |||
1196 | if (symbol_conf.event_group && evsel->nr_members > 1) { | ||
1197 | struct perf_evsel *pos; | ||
1198 | |||
1199 | perf_evsel__group_desc(evsel, buf, buflen); | ||
1200 | ev_name = buf; | ||
1201 | |||
1202 | for_each_group_member(pos, evsel) { | ||
1203 | nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; | ||
1204 | nr_events += pos->hists.stats.total_period; | ||
1205 | } | ||
1206 | } | ||
1101 | 1207 | ||
1102 | nr_samples = convert_unit(nr_samples, &unit); | 1208 | nr_samples = convert_unit(nr_samples, &unit); |
1103 | printed = scnprintf(bf, size, | 1209 | printed = scnprintf(bf, size, |
@@ -1135,6 +1241,96 @@ static inline bool is_report_browser(void *timer) | |||
1135 | return timer == NULL; | 1241 | return timer == NULL; |
1136 | } | 1242 | } |
1137 | 1243 | ||
1244 | /* | ||
1245 | * Only runtime switching of perf data file will make "input_name" point | ||
1246 | * to a malloced buffer. So add "is_input_name_malloced" flag to decide | ||
1247 | * whether we need to call free() for current "input_name" during the switch. | ||
1248 | */ | ||
1249 | static bool is_input_name_malloced = false; | ||
1250 | |||
1251 | static int switch_data_file(void) | ||
1252 | { | ||
1253 | char *pwd, *options[32], *abs_path[32], *tmp; | ||
1254 | DIR *pwd_dir; | ||
1255 | int nr_options = 0, choice = -1, ret = -1; | ||
1256 | struct dirent *dent; | ||
1257 | |||
1258 | pwd = getenv("PWD"); | ||
1259 | if (!pwd) | ||
1260 | return ret; | ||
1261 | |||
1262 | pwd_dir = opendir(pwd); | ||
1263 | if (!pwd_dir) | ||
1264 | return ret; | ||
1265 | |||
1266 | memset(options, 0, sizeof(options)); | ||
1267 | memset(options, 0, sizeof(abs_path)); | ||
1268 | |||
1269 | while ((dent = readdir(pwd_dir))) { | ||
1270 | char path[PATH_MAX]; | ||
1271 | u64 magic; | ||
1272 | char *name = dent->d_name; | ||
1273 | FILE *file; | ||
1274 | |||
1275 | if (!(dent->d_type == DT_REG)) | ||
1276 | continue; | ||
1277 | |||
1278 | snprintf(path, sizeof(path), "%s/%s", pwd, name); | ||
1279 | |||
1280 | file = fopen(path, "r"); | ||
1281 | if (!file) | ||
1282 | continue; | ||
1283 | |||
1284 | if (fread(&magic, 1, 8, file) < 8) | ||
1285 | goto close_file_and_continue; | ||
1286 | |||
1287 | if (is_perf_magic(magic)) { | ||
1288 | options[nr_options] = strdup(name); | ||
1289 | if (!options[nr_options]) | ||
1290 | goto close_file_and_continue; | ||
1291 | |||
1292 | abs_path[nr_options] = strdup(path); | ||
1293 | if (!abs_path[nr_options]) { | ||
1294 | free(options[nr_options]); | ||
1295 | ui__warning("Can't search all data files due to memory shortage.\n"); | ||
1296 | fclose(file); | ||
1297 | break; | ||
1298 | } | ||
1299 | |||
1300 | nr_options++; | ||
1301 | } | ||
1302 | |||
1303 | close_file_and_continue: | ||
1304 | fclose(file); | ||
1305 | if (nr_options >= 32) { | ||
1306 | ui__warning("Too many perf data files in PWD!\n" | ||
1307 | "Only the first 32 files will be listed.\n"); | ||
1308 | break; | ||
1309 | } | ||
1310 | } | ||
1311 | closedir(pwd_dir); | ||
1312 | |||
1313 | if (nr_options) { | ||
1314 | choice = ui__popup_menu(nr_options, options); | ||
1315 | if (choice < nr_options && choice >= 0) { | ||
1316 | tmp = strdup(abs_path[choice]); | ||
1317 | if (tmp) { | ||
1318 | if (is_input_name_malloced) | ||
1319 | free((void *)input_name); | ||
1320 | input_name = tmp; | ||
1321 | is_input_name_malloced = true; | ||
1322 | ret = 0; | ||
1323 | } else | ||
1324 | ui__warning("Data switch failed due to memory shortage!\n"); | ||
1325 | } | ||
1326 | } | ||
1327 | |||
1328 | free_popup_options(options, nr_options); | ||
1329 | free_popup_options(abs_path, nr_options); | ||
1330 | return ret; | ||
1331 | } | ||
1332 | |||
1333 | |||
1138 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | 1334 | static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, |
1139 | const char *helpline, const char *ev_name, | 1335 | const char *helpline, const char *ev_name, |
1140 | bool left_exits, | 1336 | bool left_exits, |
@@ -1169,7 +1365,8 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1169 | int choice = 0, | 1365 | int choice = 0, |
1170 | annotate = -2, zoom_dso = -2, zoom_thread = -2, | 1366 | annotate = -2, zoom_dso = -2, zoom_thread = -2, |
1171 | annotate_f = -2, annotate_t = -2, browse_map = -2; | 1367 | annotate_f = -2, annotate_t = -2, browse_map = -2; |
1172 | int scripts_comm = -2, scripts_symbol = -2, scripts_all = -2; | 1368 | int scripts_comm = -2, scripts_symbol = -2, |
1369 | scripts_all = -2, switch_data = -2; | ||
1173 | 1370 | ||
1174 | nr_options = 0; | 1371 | nr_options = 0; |
1175 | 1372 | ||
@@ -1226,6 +1423,10 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1226 | if (is_report_browser(hbt)) | 1423 | if (is_report_browser(hbt)) |
1227 | goto do_scripts; | 1424 | goto do_scripts; |
1228 | continue; | 1425 | continue; |
1426 | case 's': | ||
1427 | if (is_report_browser(hbt)) | ||
1428 | goto do_data_switch; | ||
1429 | continue; | ||
1229 | case K_F1: | 1430 | case K_F1: |
1230 | case 'h': | 1431 | case 'h': |
1231 | case '?': | 1432 | case '?': |
@@ -1245,6 +1446,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1245 | "d Zoom into current DSO\n" | 1446 | "d Zoom into current DSO\n" |
1246 | "t Zoom into current Thread\n" | 1447 | "t Zoom into current Thread\n" |
1247 | "r Run available scripts('perf report' only)\n" | 1448 | "r Run available scripts('perf report' only)\n" |
1449 | "s Switch to another data file in PWD ('perf report' only)\n" | ||
1248 | "P Print histograms to perf.hist.N\n" | 1450 | "P Print histograms to perf.hist.N\n" |
1249 | "V Verbose (DSO names in callchains, etc)\n" | 1451 | "V Verbose (DSO names in callchains, etc)\n" |
1250 | "/ Filter symbol by name"); | 1452 | "/ Filter symbol by name"); |
@@ -1352,6 +1554,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, | |||
1352 | if (asprintf(&options[nr_options], "Run scripts for all samples") > 0) | 1554 | if (asprintf(&options[nr_options], "Run scripts for all samples") > 0) |
1353 | scripts_all = nr_options++; | 1555 | scripts_all = nr_options++; |
1354 | 1556 | ||
1557 | if (is_report_browser(hbt) && asprintf(&options[nr_options], | ||
1558 | "Switch to another data file in PWD") > 0) | ||
1559 | switch_data = nr_options++; | ||
1355 | add_exit_option: | 1560 | add_exit_option: |
1356 | options[nr_options++] = (char *)"Exit"; | 1561 | options[nr_options++] = (char *)"Exit"; |
1357 | retry_popup_menu: | 1562 | retry_popup_menu: |
@@ -1462,6 +1667,16 @@ do_scripts: | |||
1462 | 1667 | ||
1463 | script_browse(script_opt); | 1668 | script_browse(script_opt); |
1464 | } | 1669 | } |
1670 | /* Switch to another data file */ | ||
1671 | else if (choice == switch_data) { | ||
1672 | do_data_switch: | ||
1673 | if (!switch_data_file()) { | ||
1674 | key = K_SWITCH_INPUT_DATA; | ||
1675 | break; | ||
1676 | } else | ||
1677 | ui__warning("Won't switch the data files due to\n" | ||
1678 | "no valid data file get selected!\n"); | ||
1679 | } | ||
1465 | } | 1680 | } |
1466 | out_free_stack: | 1681 | out_free_stack: |
1467 | pstack__delete(fstack); | 1682 | pstack__delete(fstack); |
@@ -1494,6 +1709,16 @@ static void perf_evsel_menu__write(struct ui_browser *browser, | |||
1494 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : | 1709 | ui_browser__set_color(browser, current_entry ? HE_COLORSET_SELECTED : |
1495 | HE_COLORSET_NORMAL); | 1710 | HE_COLORSET_NORMAL); |
1496 | 1711 | ||
1712 | if (symbol_conf.event_group && evsel->nr_members > 1) { | ||
1713 | struct perf_evsel *pos; | ||
1714 | |||
1715 | ev_name = perf_evsel__group_name(evsel); | ||
1716 | |||
1717 | for_each_group_member(pos, evsel) { | ||
1718 | nr_events += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; | ||
1719 | } | ||
1720 | } | ||
1721 | |||
1497 | nr_events = convert_unit(nr_events, &unit); | 1722 | nr_events = convert_unit(nr_events, &unit); |
1498 | printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, | 1723 | printed = scnprintf(bf, sizeof(bf), "%lu%c%s%s", nr_events, |
1499 | unit, unit == ' ' ? "" : " ", ev_name); | 1724 | unit, unit == ' ' ? "" : " ", ev_name); |
@@ -1578,6 +1803,7 @@ browse_hists: | |||
1578 | "Do you really want to exit?")) | 1803 | "Do you really want to exit?")) |
1579 | continue; | 1804 | continue; |
1580 | /* Fall thru */ | 1805 | /* Fall thru */ |
1806 | case K_SWITCH_INPUT_DATA: | ||
1581 | case 'q': | 1807 | case 'q': |
1582 | case CTRL('c'): | 1808 | case CTRL('c'): |
1583 | goto out; | 1809 | goto out; |
@@ -1604,8 +1830,19 @@ out: | |||
1604 | return key; | 1830 | return key; |
1605 | } | 1831 | } |
1606 | 1832 | ||
1833 | static bool filter_group_entries(struct ui_browser *self __maybe_unused, | ||
1834 | void *entry) | ||
1835 | { | ||
1836 | struct perf_evsel *evsel = list_entry(entry, struct perf_evsel, node); | ||
1837 | |||
1838 | if (symbol_conf.event_group && !perf_evsel__is_group_leader(evsel)) | ||
1839 | return true; | ||
1840 | |||
1841 | return false; | ||
1842 | } | ||
1843 | |||
1607 | static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, | 1844 | static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, |
1608 | const char *help, | 1845 | int nr_entries, const char *help, |
1609 | struct hist_browser_timer *hbt, | 1846 | struct hist_browser_timer *hbt, |
1610 | struct perf_session_env *env) | 1847 | struct perf_session_env *env) |
1611 | { | 1848 | { |
@@ -1616,7 +1853,8 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, | |||
1616 | .refresh = ui_browser__list_head_refresh, | 1853 | .refresh = ui_browser__list_head_refresh, |
1617 | .seek = ui_browser__list_head_seek, | 1854 | .seek = ui_browser__list_head_seek, |
1618 | .write = perf_evsel_menu__write, | 1855 | .write = perf_evsel_menu__write, |
1619 | .nr_entries = evlist->nr_entries, | 1856 | .filter = filter_group_entries, |
1857 | .nr_entries = nr_entries, | ||
1620 | .priv = evlist, | 1858 | .priv = evlist, |
1621 | }, | 1859 | }, |
1622 | .env = env, | 1860 | .env = env, |
@@ -1632,20 +1870,37 @@ static int __perf_evlist__tui_browse_hists(struct perf_evlist *evlist, | |||
1632 | menu.b.width = line_len; | 1870 | menu.b.width = line_len; |
1633 | } | 1871 | } |
1634 | 1872 | ||
1635 | return perf_evsel_menu__run(&menu, evlist->nr_entries, help, hbt); | 1873 | return perf_evsel_menu__run(&menu, nr_entries, help, hbt); |
1636 | } | 1874 | } |
1637 | 1875 | ||
1638 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, | 1876 | int perf_evlist__tui_browse_hists(struct perf_evlist *evlist, const char *help, |
1639 | struct hist_browser_timer *hbt, | 1877 | struct hist_browser_timer *hbt, |
1640 | struct perf_session_env *env) | 1878 | struct perf_session_env *env) |
1641 | { | 1879 | { |
1642 | if (evlist->nr_entries == 1) { | 1880 | int nr_entries = evlist->nr_entries; |
1881 | |||
1882 | single_entry: | ||
1883 | if (nr_entries == 1) { | ||
1643 | struct perf_evsel *first = list_entry(evlist->entries.next, | 1884 | struct perf_evsel *first = list_entry(evlist->entries.next, |
1644 | struct perf_evsel, node); | 1885 | struct perf_evsel, node); |
1645 | const char *ev_name = perf_evsel__name(first); | 1886 | const char *ev_name = perf_evsel__name(first); |
1646 | return perf_evsel__hists_browse(first, evlist->nr_entries, help, | 1887 | |
1888 | return perf_evsel__hists_browse(first, nr_entries, help, | ||
1647 | ev_name, false, hbt, env); | 1889 | ev_name, false, hbt, env); |
1648 | } | 1890 | } |
1649 | 1891 | ||
1650 | return __perf_evlist__tui_browse_hists(evlist, help, hbt, env); | 1892 | if (symbol_conf.event_group) { |
1893 | struct perf_evsel *pos; | ||
1894 | |||
1895 | nr_entries = 0; | ||
1896 | list_for_each_entry(pos, &evlist->entries, node) | ||
1897 | if (perf_evsel__is_group_leader(pos)) | ||
1898 | nr_entries++; | ||
1899 | |||
1900 | if (nr_entries == 1) | ||
1901 | goto single_entry; | ||
1902 | } | ||
1903 | |||
1904 | return __perf_evlist__tui_browse_hists(evlist, nr_entries, help, | ||
1905 | hbt, env); | ||
1651 | } | 1906 | } |
diff --git a/tools/perf/ui/gtk/annotate.c b/tools/perf/ui/gtk/annotate.c new file mode 100644 index 000000000000..7d8dc581a545 --- /dev/null +++ b/tools/perf/ui/gtk/annotate.c | |||
@@ -0,0 +1,229 @@ | |||
1 | #include "gtk.h" | ||
2 | #include "util/debug.h" | ||
3 | #include "util/annotate.h" | ||
4 | #include "ui/helpline.h" | ||
5 | |||
6 | |||
7 | enum { | ||
8 | ANN_COL__PERCENT, | ||
9 | ANN_COL__OFFSET, | ||
10 | ANN_COL__LINE, | ||
11 | |||
12 | MAX_ANN_COLS | ||
13 | }; | ||
14 | |||
15 | static const char *const col_names[] = { | ||
16 | "Overhead", | ||
17 | "Offset", | ||
18 | "Line" | ||
19 | }; | ||
20 | |||
21 | static int perf_gtk__get_percent(char *buf, size_t size, struct symbol *sym, | ||
22 | struct disasm_line *dl, int evidx) | ||
23 | { | ||
24 | struct sym_hist *symhist; | ||
25 | double percent = 0.0; | ||
26 | const char *markup; | ||
27 | int ret = 0; | ||
28 | |||
29 | strcpy(buf, ""); | ||
30 | |||
31 | if (dl->offset == (s64) -1) | ||
32 | return 0; | ||
33 | |||
34 | symhist = annotation__histogram(symbol__annotation(sym), evidx); | ||
35 | if (!symhist->addr[dl->offset]) | ||
36 | return 0; | ||
37 | |||
38 | percent = 100.0 * symhist->addr[dl->offset] / symhist->sum; | ||
39 | |||
40 | markup = perf_gtk__get_percent_color(percent); | ||
41 | if (markup) | ||
42 | ret += scnprintf(buf, size, "%s", markup); | ||
43 | ret += scnprintf(buf + ret, size - ret, "%6.2f%%", percent); | ||
44 | if (markup) | ||
45 | ret += scnprintf(buf + ret, size - ret, "</span>"); | ||
46 | |||
47 | return ret; | ||
48 | } | ||
49 | |||
50 | static int perf_gtk__get_offset(char *buf, size_t size, struct symbol *sym, | ||
51 | struct map *map, struct disasm_line *dl) | ||
52 | { | ||
53 | u64 start = map__rip_2objdump(map, sym->start); | ||
54 | |||
55 | strcpy(buf, ""); | ||
56 | |||
57 | if (dl->offset == (s64) -1) | ||
58 | return 0; | ||
59 | |||
60 | return scnprintf(buf, size, "%"PRIx64, start + dl->offset); | ||
61 | } | ||
62 | |||
63 | static int perf_gtk__get_line(char *buf, size_t size, struct disasm_line *dl) | ||
64 | { | ||
65 | int ret = 0; | ||
66 | char *line = g_markup_escape_text(dl->line, -1); | ||
67 | const char *markup = "<span fgcolor='gray'>"; | ||
68 | |||
69 | strcpy(buf, ""); | ||
70 | |||
71 | if (!line) | ||
72 | return 0; | ||
73 | |||
74 | if (dl->offset != (s64) -1) | ||
75 | markup = NULL; | ||
76 | |||
77 | if (markup) | ||
78 | ret += scnprintf(buf, size, "%s", markup); | ||
79 | ret += scnprintf(buf + ret, size - ret, "%s", line); | ||
80 | if (markup) | ||
81 | ret += scnprintf(buf + ret, size - ret, "</span>"); | ||
82 | |||
83 | g_free(line); | ||
84 | return ret; | ||
85 | } | ||
86 | |||
87 | static int perf_gtk__annotate_symbol(GtkWidget *window, struct symbol *sym, | ||
88 | struct map *map, int evidx, | ||
89 | struct hist_browser_timer *hbt __maybe_unused) | ||
90 | { | ||
91 | struct disasm_line *pos, *n; | ||
92 | struct annotation *notes; | ||
93 | GType col_types[MAX_ANN_COLS]; | ||
94 | GtkCellRenderer *renderer; | ||
95 | GtkListStore *store; | ||
96 | GtkWidget *view; | ||
97 | int i; | ||
98 | char s[512]; | ||
99 | |||
100 | notes = symbol__annotation(sym); | ||
101 | |||
102 | for (i = 0; i < MAX_ANN_COLS; i++) { | ||
103 | col_types[i] = G_TYPE_STRING; | ||
104 | } | ||
105 | store = gtk_list_store_newv(MAX_ANN_COLS, col_types); | ||
106 | |||
107 | view = gtk_tree_view_new(); | ||
108 | renderer = gtk_cell_renderer_text_new(); | ||
109 | |||
110 | for (i = 0; i < MAX_ANN_COLS; i++) { | ||
111 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
112 | -1, col_names[i], renderer, "markup", | ||
113 | i, NULL); | ||
114 | } | ||
115 | |||
116 | gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); | ||
117 | g_object_unref(GTK_TREE_MODEL(store)); | ||
118 | |||
119 | list_for_each_entry(pos, ¬es->src->source, node) { | ||
120 | GtkTreeIter iter; | ||
121 | |||
122 | gtk_list_store_append(store, &iter); | ||
123 | |||
124 | if (perf_gtk__get_percent(s, sizeof(s), sym, pos, evidx)) | ||
125 | gtk_list_store_set(store, &iter, ANN_COL__PERCENT, s, -1); | ||
126 | if (perf_gtk__get_offset(s, sizeof(s), sym, map, pos)) | ||
127 | gtk_list_store_set(store, &iter, ANN_COL__OFFSET, s, -1); | ||
128 | if (perf_gtk__get_line(s, sizeof(s), pos)) | ||
129 | gtk_list_store_set(store, &iter, ANN_COL__LINE, s, -1); | ||
130 | } | ||
131 | |||
132 | gtk_container_add(GTK_CONTAINER(window), view); | ||
133 | |||
134 | list_for_each_entry_safe(pos, n, ¬es->src->source, node) { | ||
135 | list_del(&pos->node); | ||
136 | disasm_line__free(pos); | ||
137 | } | ||
138 | |||
139 | return 0; | ||
140 | } | ||
141 | |||
142 | int symbol__gtk_annotate(struct symbol *sym, struct map *map, int evidx, | ||
143 | struct hist_browser_timer *hbt) | ||
144 | { | ||
145 | GtkWidget *window; | ||
146 | GtkWidget *notebook; | ||
147 | GtkWidget *scrolled_window; | ||
148 | GtkWidget *tab_label; | ||
149 | |||
150 | if (map->dso->annotate_warned) | ||
151 | return -1; | ||
152 | |||
153 | if (symbol__annotate(sym, map, 0) < 0) { | ||
154 | ui__error("%s", ui_helpline__current); | ||
155 | return -1; | ||
156 | } | ||
157 | |||
158 | if (perf_gtk__is_active_context(pgctx)) { | ||
159 | window = pgctx->main_window; | ||
160 | notebook = pgctx->notebook; | ||
161 | } else { | ||
162 | GtkWidget *vbox; | ||
163 | GtkWidget *infobar; | ||
164 | GtkWidget *statbar; | ||
165 | |||
166 | signal(SIGSEGV, perf_gtk__signal); | ||
167 | signal(SIGFPE, perf_gtk__signal); | ||
168 | signal(SIGINT, perf_gtk__signal); | ||
169 | signal(SIGQUIT, perf_gtk__signal); | ||
170 | signal(SIGTERM, perf_gtk__signal); | ||
171 | |||
172 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | ||
173 | gtk_window_set_title(GTK_WINDOW(window), "perf annotate"); | ||
174 | |||
175 | g_signal_connect(window, "delete_event", gtk_main_quit, NULL); | ||
176 | |||
177 | pgctx = perf_gtk__activate_context(window); | ||
178 | if (!pgctx) | ||
179 | return -1; | ||
180 | |||
181 | vbox = gtk_vbox_new(FALSE, 0); | ||
182 | notebook = gtk_notebook_new(); | ||
183 | pgctx->notebook = notebook; | ||
184 | |||
185 | gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); | ||
186 | |||
187 | infobar = perf_gtk__setup_info_bar(); | ||
188 | if (infobar) { | ||
189 | gtk_box_pack_start(GTK_BOX(vbox), infobar, | ||
190 | FALSE, FALSE, 0); | ||
191 | } | ||
192 | |||
193 | statbar = perf_gtk__setup_statusbar(); | ||
194 | gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); | ||
195 | |||
196 | gtk_container_add(GTK_CONTAINER(window), vbox); | ||
197 | } | ||
198 | |||
199 | scrolled_window = gtk_scrolled_window_new(NULL, NULL); | ||
200 | tab_label = gtk_label_new(sym->name); | ||
201 | |||
202 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), | ||
203 | GTK_POLICY_AUTOMATIC, | ||
204 | GTK_POLICY_AUTOMATIC); | ||
205 | |||
206 | gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, | ||
207 | tab_label); | ||
208 | |||
209 | perf_gtk__annotate_symbol(scrolled_window, sym, map, evidx, hbt); | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | void perf_gtk__show_annotations(void) | ||
214 | { | ||
215 | GtkWidget *window; | ||
216 | |||
217 | if (!perf_gtk__is_active_context(pgctx)) | ||
218 | return; | ||
219 | |||
220 | window = pgctx->main_window; | ||
221 | gtk_widget_show_all(window); | ||
222 | |||
223 | perf_gtk__resize_window(window); | ||
224 | gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); | ||
225 | |||
226 | gtk_main(); | ||
227 | |||
228 | perf_gtk__deactivate_context(&pgctx); | ||
229 | } | ||
diff --git a/tools/perf/ui/gtk/browser.c b/tools/perf/ui/gtk/browser.c index 253b6219a39e..c95012cdb438 100644 --- a/tools/perf/ui/gtk/browser.c +++ b/tools/perf/ui/gtk/browser.c | |||
@@ -8,15 +8,13 @@ | |||
8 | 8 | ||
9 | #include <signal.h> | 9 | #include <signal.h> |
10 | 10 | ||
11 | #define MAX_COLUMNS 32 | 11 | void perf_gtk__signal(int sig) |
12 | |||
13 | static void perf_gtk__signal(int sig) | ||
14 | { | 12 | { |
15 | perf_gtk__exit(false); | 13 | perf_gtk__exit(false); |
16 | psignal(sig, "perf"); | 14 | psignal(sig, "perf"); |
17 | } | 15 | } |
18 | 16 | ||
19 | static void perf_gtk__resize_window(GtkWidget *window) | 17 | void perf_gtk__resize_window(GtkWidget *window) |
20 | { | 18 | { |
21 | GdkRectangle rect; | 19 | GdkRectangle rect; |
22 | GdkScreen *screen; | 20 | GdkScreen *screen; |
@@ -36,7 +34,7 @@ static void perf_gtk__resize_window(GtkWidget *window) | |||
36 | gtk_window_resize(GTK_WINDOW(window), width, height); | 34 | gtk_window_resize(GTK_WINDOW(window), width, height); |
37 | } | 35 | } |
38 | 36 | ||
39 | static const char *perf_gtk__get_percent_color(double percent) | 37 | const char *perf_gtk__get_percent_color(double percent) |
40 | { | 38 | { |
41 | if (percent >= MIN_RED) | 39 | if (percent >= MIN_RED) |
42 | return "<span fgcolor='red'>"; | 40 | return "<span fgcolor='red'>"; |
@@ -45,155 +43,8 @@ static const char *perf_gtk__get_percent_color(double percent) | |||
45 | return NULL; | 43 | return NULL; |
46 | } | 44 | } |
47 | 45 | ||
48 | #define HPP__COLOR_FN(_name, _field) \ | ||
49 | static int perf_gtk__hpp_color_ ## _name(struct perf_hpp *hpp, \ | ||
50 | struct hist_entry *he) \ | ||
51 | { \ | ||
52 | struct hists *hists = he->hists; \ | ||
53 | double percent = 100.0 * he->stat._field / hists->stats.total_period; \ | ||
54 | const char *markup; \ | ||
55 | int ret = 0; \ | ||
56 | \ | ||
57 | markup = perf_gtk__get_percent_color(percent); \ | ||
58 | if (markup) \ | ||
59 | ret += scnprintf(hpp->buf, hpp->size, "%s", markup); \ | ||
60 | ret += scnprintf(hpp->buf + ret, hpp->size - ret, "%6.2f%%", percent); \ | ||
61 | if (markup) \ | ||
62 | ret += scnprintf(hpp->buf + ret, hpp->size - ret, "</span>"); \ | ||
63 | \ | ||
64 | return ret; \ | ||
65 | } | ||
66 | |||
67 | HPP__COLOR_FN(overhead, period) | ||
68 | HPP__COLOR_FN(overhead_sys, period_sys) | ||
69 | HPP__COLOR_FN(overhead_us, period_us) | ||
70 | HPP__COLOR_FN(overhead_guest_sys, period_guest_sys) | ||
71 | HPP__COLOR_FN(overhead_guest_us, period_guest_us) | ||
72 | |||
73 | #undef HPP__COLOR_FN | ||
74 | |||
75 | void perf_gtk__init_hpp(void) | ||
76 | { | ||
77 | perf_hpp__init(); | ||
78 | |||
79 | perf_hpp__format[PERF_HPP__OVERHEAD].color = | ||
80 | perf_gtk__hpp_color_overhead; | ||
81 | perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = | ||
82 | perf_gtk__hpp_color_overhead_sys; | ||
83 | perf_hpp__format[PERF_HPP__OVERHEAD_US].color = | ||
84 | perf_gtk__hpp_color_overhead_us; | ||
85 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = | ||
86 | perf_gtk__hpp_color_overhead_guest_sys; | ||
87 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = | ||
88 | perf_gtk__hpp_color_overhead_guest_us; | ||
89 | } | ||
90 | |||
91 | static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) | ||
92 | { | ||
93 | GType col_types[MAX_COLUMNS]; | ||
94 | GtkCellRenderer *renderer; | ||
95 | struct sort_entry *se; | ||
96 | GtkListStore *store; | ||
97 | struct rb_node *nd; | ||
98 | GtkWidget *view; | ||
99 | int i, col_idx; | ||
100 | int nr_cols; | ||
101 | char s[512]; | ||
102 | |||
103 | struct perf_hpp hpp = { | ||
104 | .buf = s, | ||
105 | .size = sizeof(s), | ||
106 | }; | ||
107 | |||
108 | nr_cols = 0; | ||
109 | |||
110 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | ||
111 | if (!perf_hpp__format[i].cond) | ||
112 | continue; | ||
113 | |||
114 | col_types[nr_cols++] = G_TYPE_STRING; | ||
115 | } | ||
116 | |||
117 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
118 | if (se->elide) | ||
119 | continue; | ||
120 | |||
121 | col_types[nr_cols++] = G_TYPE_STRING; | ||
122 | } | ||
123 | |||
124 | store = gtk_list_store_newv(nr_cols, col_types); | ||
125 | |||
126 | view = gtk_tree_view_new(); | ||
127 | |||
128 | renderer = gtk_cell_renderer_text_new(); | ||
129 | |||
130 | col_idx = 0; | ||
131 | |||
132 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | ||
133 | if (!perf_hpp__format[i].cond) | ||
134 | continue; | ||
135 | |||
136 | perf_hpp__format[i].header(&hpp); | ||
137 | |||
138 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
139 | -1, s, | ||
140 | renderer, "markup", | ||
141 | col_idx++, NULL); | ||
142 | } | ||
143 | |||
144 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
145 | if (se->elide) | ||
146 | continue; | ||
147 | |||
148 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
149 | -1, se->se_header, | ||
150 | renderer, "text", | ||
151 | col_idx++, NULL); | ||
152 | } | ||
153 | |||
154 | gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); | ||
155 | |||
156 | g_object_unref(GTK_TREE_MODEL(store)); | ||
157 | |||
158 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { | ||
159 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | ||
160 | GtkTreeIter iter; | ||
161 | |||
162 | if (h->filtered) | ||
163 | continue; | ||
164 | |||
165 | gtk_list_store_append(store, &iter); | ||
166 | |||
167 | col_idx = 0; | ||
168 | |||
169 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | ||
170 | if (!perf_hpp__format[i].cond) | ||
171 | continue; | ||
172 | |||
173 | if (perf_hpp__format[i].color) | ||
174 | perf_hpp__format[i].color(&hpp, h); | ||
175 | else | ||
176 | perf_hpp__format[i].entry(&hpp, h); | ||
177 | |||
178 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | ||
179 | } | ||
180 | |||
181 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
182 | if (se->elide) | ||
183 | continue; | ||
184 | |||
185 | se->se_snprintf(h, s, ARRAY_SIZE(s), | ||
186 | hists__col_len(hists, se->se_width_idx)); | ||
187 | |||
188 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | gtk_container_add(GTK_CONTAINER(window), view); | ||
193 | } | ||
194 | |||
195 | #ifdef HAVE_GTK_INFO_BAR | 46 | #ifdef HAVE_GTK_INFO_BAR |
196 | static GtkWidget *perf_gtk__setup_info_bar(void) | 47 | GtkWidget *perf_gtk__setup_info_bar(void) |
197 | { | 48 | { |
198 | GtkWidget *info_bar; | 49 | GtkWidget *info_bar; |
199 | GtkWidget *label; | 50 | GtkWidget *label; |
@@ -220,7 +71,7 @@ static GtkWidget *perf_gtk__setup_info_bar(void) | |||
220 | } | 71 | } |
221 | #endif | 72 | #endif |
222 | 73 | ||
223 | static GtkWidget *perf_gtk__setup_statusbar(void) | 74 | GtkWidget *perf_gtk__setup_statusbar(void) |
224 | { | 75 | { |
225 | GtkWidget *stbar; | 76 | GtkWidget *stbar; |
226 | unsigned ctxid; | 77 | unsigned ctxid; |
@@ -234,79 +85,3 @@ static GtkWidget *perf_gtk__setup_statusbar(void) | |||
234 | 85 | ||
235 | return stbar; | 86 | return stbar; |
236 | } | 87 | } |
237 | |||
238 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, | ||
239 | const char *help, | ||
240 | struct hist_browser_timer *hbt __maybe_unused) | ||
241 | { | ||
242 | struct perf_evsel *pos; | ||
243 | GtkWidget *vbox; | ||
244 | GtkWidget *notebook; | ||
245 | GtkWidget *info_bar; | ||
246 | GtkWidget *statbar; | ||
247 | GtkWidget *window; | ||
248 | |||
249 | signal(SIGSEGV, perf_gtk__signal); | ||
250 | signal(SIGFPE, perf_gtk__signal); | ||
251 | signal(SIGINT, perf_gtk__signal); | ||
252 | signal(SIGQUIT, perf_gtk__signal); | ||
253 | signal(SIGTERM, perf_gtk__signal); | ||
254 | |||
255 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | ||
256 | |||
257 | gtk_window_set_title(GTK_WINDOW(window), "perf report"); | ||
258 | |||
259 | g_signal_connect(window, "delete_event", gtk_main_quit, NULL); | ||
260 | |||
261 | pgctx = perf_gtk__activate_context(window); | ||
262 | if (!pgctx) | ||
263 | return -1; | ||
264 | |||
265 | vbox = gtk_vbox_new(FALSE, 0); | ||
266 | |||
267 | notebook = gtk_notebook_new(); | ||
268 | |||
269 | list_for_each_entry(pos, &evlist->entries, node) { | ||
270 | struct hists *hists = &pos->hists; | ||
271 | const char *evname = perf_evsel__name(pos); | ||
272 | GtkWidget *scrolled_window; | ||
273 | GtkWidget *tab_label; | ||
274 | |||
275 | scrolled_window = gtk_scrolled_window_new(NULL, NULL); | ||
276 | |||
277 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), | ||
278 | GTK_POLICY_AUTOMATIC, | ||
279 | GTK_POLICY_AUTOMATIC); | ||
280 | |||
281 | perf_gtk__show_hists(scrolled_window, hists); | ||
282 | |||
283 | tab_label = gtk_label_new(evname); | ||
284 | |||
285 | gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label); | ||
286 | } | ||
287 | |||
288 | gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); | ||
289 | |||
290 | info_bar = perf_gtk__setup_info_bar(); | ||
291 | if (info_bar) | ||
292 | gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0); | ||
293 | |||
294 | statbar = perf_gtk__setup_statusbar(); | ||
295 | gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); | ||
296 | |||
297 | gtk_container_add(GTK_CONTAINER(window), vbox); | ||
298 | |||
299 | gtk_widget_show_all(window); | ||
300 | |||
301 | perf_gtk__resize_window(window); | ||
302 | |||
303 | gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); | ||
304 | |||
305 | ui_helpline__push(help); | ||
306 | |||
307 | gtk_main(); | ||
308 | |||
309 | perf_gtk__deactivate_context(&pgctx); | ||
310 | |||
311 | return 0; | ||
312 | } | ||
diff --git a/tools/perf/ui/gtk/gtk.h b/tools/perf/ui/gtk/gtk.h index 856320e2cc05..3d96785ef155 100644 --- a/tools/perf/ui/gtk/gtk.h +++ b/tools/perf/ui/gtk/gtk.h | |||
@@ -10,6 +10,7 @@ | |||
10 | 10 | ||
11 | struct perf_gtk_context { | 11 | struct perf_gtk_context { |
12 | GtkWidget *main_window; | 12 | GtkWidget *main_window; |
13 | GtkWidget *notebook; | ||
13 | 14 | ||
14 | #ifdef HAVE_GTK_INFO_BAR | 15 | #ifdef HAVE_GTK_INFO_BAR |
15 | GtkWidget *info_bar; | 16 | GtkWidget *info_bar; |
@@ -33,7 +34,14 @@ void perf_gtk__init_helpline(void); | |||
33 | void perf_gtk__init_progress(void); | 34 | void perf_gtk__init_progress(void); |
34 | void perf_gtk__init_hpp(void); | 35 | void perf_gtk__init_hpp(void); |
35 | 36 | ||
36 | #ifndef HAVE_GTK_INFO_BAR | 37 | void perf_gtk__signal(int sig); |
38 | void perf_gtk__resize_window(GtkWidget *window); | ||
39 | const char *perf_gtk__get_percent_color(double percent); | ||
40 | GtkWidget *perf_gtk__setup_statusbar(void); | ||
41 | |||
42 | #ifdef HAVE_GTK_INFO_BAR | ||
43 | GtkWidget *perf_gtk__setup_info_bar(void); | ||
44 | #else | ||
37 | static inline GtkWidget *perf_gtk__setup_info_bar(void) | 45 | static inline GtkWidget *perf_gtk__setup_info_bar(void) |
38 | { | 46 | { |
39 | return NULL; | 47 | return NULL; |
diff --git a/tools/perf/ui/gtk/helpline.c b/tools/perf/ui/gtk/helpline.c index 5db4432ff12a..3388cbd12186 100644 --- a/tools/perf/ui/gtk/helpline.c +++ b/tools/perf/ui/gtk/helpline.c | |||
@@ -24,17 +24,7 @@ static void gtk_helpline_push(const char *msg) | |||
24 | pgctx->statbar_ctx_id, msg); | 24 | pgctx->statbar_ctx_id, msg); |
25 | } | 25 | } |
26 | 26 | ||
27 | static struct ui_helpline gtk_helpline_fns = { | 27 | static int gtk_helpline_show(const char *fmt, va_list ap) |
28 | .pop = gtk_helpline_pop, | ||
29 | .push = gtk_helpline_push, | ||
30 | }; | ||
31 | |||
32 | void perf_gtk__init_helpline(void) | ||
33 | { | ||
34 | helpline_fns = >k_helpline_fns; | ||
35 | } | ||
36 | |||
37 | int perf_gtk__show_helpline(const char *fmt, va_list ap) | ||
38 | { | 28 | { |
39 | int ret; | 29 | int ret; |
40 | char *ptr; | 30 | char *ptr; |
@@ -54,3 +44,14 @@ int perf_gtk__show_helpline(const char *fmt, va_list ap) | |||
54 | 44 | ||
55 | return ret; | 45 | return ret; |
56 | } | 46 | } |
47 | |||
48 | static struct ui_helpline gtk_helpline_fns = { | ||
49 | .pop = gtk_helpline_pop, | ||
50 | .push = gtk_helpline_push, | ||
51 | .show = gtk_helpline_show, | ||
52 | }; | ||
53 | |||
54 | void perf_gtk__init_helpline(void) | ||
55 | { | ||
56 | helpline_fns = >k_helpline_fns; | ||
57 | } | ||
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c new file mode 100644 index 000000000000..1e764a8ad259 --- /dev/null +++ b/tools/perf/ui/gtk/hists.c | |||
@@ -0,0 +1,312 @@ | |||
1 | #include "../evlist.h" | ||
2 | #include "../cache.h" | ||
3 | #include "../evsel.h" | ||
4 | #include "../sort.h" | ||
5 | #include "../hist.h" | ||
6 | #include "../helpline.h" | ||
7 | #include "gtk.h" | ||
8 | |||
9 | #define MAX_COLUMNS 32 | ||
10 | |||
11 | static int __percent_color_snprintf(char *buf, size_t size, double percent) | ||
12 | { | ||
13 | int ret = 0; | ||
14 | const char *markup; | ||
15 | |||
16 | markup = perf_gtk__get_percent_color(percent); | ||
17 | if (markup) | ||
18 | ret += scnprintf(buf, size, markup); | ||
19 | |||
20 | ret += scnprintf(buf + ret, size - ret, " %6.2f%%", percent); | ||
21 | |||
22 | if (markup) | ||
23 | ret += scnprintf(buf + ret, size - ret, "</span>"); | ||
24 | |||
25 | return ret; | ||
26 | } | ||
27 | |||
28 | |||
29 | static int __hpp__color_fmt(struct perf_hpp *hpp, struct hist_entry *he, | ||
30 | u64 (*get_field)(struct hist_entry *)) | ||
31 | { | ||
32 | int ret; | ||
33 | double percent = 0.0; | ||
34 | struct hists *hists = he->hists; | ||
35 | |||
36 | if (hists->stats.total_period) | ||
37 | percent = 100.0 * get_field(he) / hists->stats.total_period; | ||
38 | |||
39 | ret = __percent_color_snprintf(hpp->buf, hpp->size, percent); | ||
40 | |||
41 | if (symbol_conf.event_group) { | ||
42 | int prev_idx, idx_delta; | ||
43 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
44 | struct hist_entry *pair; | ||
45 | int nr_members = evsel->nr_members; | ||
46 | |||
47 | if (nr_members <= 1) | ||
48 | return ret; | ||
49 | |||
50 | prev_idx = perf_evsel__group_idx(evsel); | ||
51 | |||
52 | list_for_each_entry(pair, &he->pairs.head, pairs.node) { | ||
53 | u64 period = get_field(pair); | ||
54 | u64 total = pair->hists->stats.total_period; | ||
55 | |||
56 | evsel = hists_to_evsel(pair->hists); | ||
57 | idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1; | ||
58 | |||
59 | while (idx_delta--) { | ||
60 | /* | ||
61 | * zero-fill group members in the middle which | ||
62 | * have no sample | ||
63 | */ | ||
64 | ret += __percent_color_snprintf(hpp->buf + ret, | ||
65 | hpp->size - ret, | ||
66 | 0.0); | ||
67 | } | ||
68 | |||
69 | percent = 100.0 * period / total; | ||
70 | ret += __percent_color_snprintf(hpp->buf + ret, | ||
71 | hpp->size - ret, | ||
72 | percent); | ||
73 | |||
74 | prev_idx = perf_evsel__group_idx(evsel); | ||
75 | } | ||
76 | |||
77 | idx_delta = nr_members - prev_idx - 1; | ||
78 | |||
79 | while (idx_delta--) { | ||
80 | /* | ||
81 | * zero-fill group members at last which have no sample | ||
82 | */ | ||
83 | ret += __percent_color_snprintf(hpp->buf + ret, | ||
84 | hpp->size - ret, | ||
85 | 0.0); | ||
86 | } | ||
87 | } | ||
88 | return ret; | ||
89 | } | ||
90 | |||
91 | #define __HPP_COLOR_PERCENT_FN(_type, _field) \ | ||
92 | static u64 he_get_##_field(struct hist_entry *he) \ | ||
93 | { \ | ||
94 | return he->stat._field; \ | ||
95 | } \ | ||
96 | \ | ||
97 | static int perf_gtk__hpp_color_##_type(struct perf_hpp *hpp, \ | ||
98 | struct hist_entry *he) \ | ||
99 | { \ | ||
100 | return __hpp__color_fmt(hpp, he, he_get_##_field); \ | ||
101 | } | ||
102 | |||
103 | __HPP_COLOR_PERCENT_FN(overhead, period) | ||
104 | __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys) | ||
105 | __HPP_COLOR_PERCENT_FN(overhead_us, period_us) | ||
106 | __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys) | ||
107 | __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) | ||
108 | |||
109 | #undef __HPP_COLOR_PERCENT_FN | ||
110 | |||
111 | |||
112 | void perf_gtk__init_hpp(void) | ||
113 | { | ||
114 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
115 | |||
116 | perf_hpp__init(); | ||
117 | |||
118 | perf_hpp__format[PERF_HPP__OVERHEAD].color = | ||
119 | perf_gtk__hpp_color_overhead; | ||
120 | perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = | ||
121 | perf_gtk__hpp_color_overhead_sys; | ||
122 | perf_hpp__format[PERF_HPP__OVERHEAD_US].color = | ||
123 | perf_gtk__hpp_color_overhead_us; | ||
124 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].color = | ||
125 | perf_gtk__hpp_color_overhead_guest_sys; | ||
126 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].color = | ||
127 | perf_gtk__hpp_color_overhead_guest_us; | ||
128 | } | ||
129 | |||
130 | static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists) | ||
131 | { | ||
132 | struct perf_hpp_fmt *fmt; | ||
133 | GType col_types[MAX_COLUMNS]; | ||
134 | GtkCellRenderer *renderer; | ||
135 | struct sort_entry *se; | ||
136 | GtkListStore *store; | ||
137 | struct rb_node *nd; | ||
138 | GtkWidget *view; | ||
139 | int col_idx; | ||
140 | int nr_cols; | ||
141 | char s[512]; | ||
142 | |||
143 | struct perf_hpp hpp = { | ||
144 | .buf = s, | ||
145 | .size = sizeof(s), | ||
146 | .ptr = hists_to_evsel(hists), | ||
147 | }; | ||
148 | |||
149 | nr_cols = 0; | ||
150 | |||
151 | perf_hpp__for_each_format(fmt) | ||
152 | col_types[nr_cols++] = G_TYPE_STRING; | ||
153 | |||
154 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
155 | if (se->elide) | ||
156 | continue; | ||
157 | |||
158 | col_types[nr_cols++] = G_TYPE_STRING; | ||
159 | } | ||
160 | |||
161 | store = gtk_list_store_newv(nr_cols, col_types); | ||
162 | |||
163 | view = gtk_tree_view_new(); | ||
164 | |||
165 | renderer = gtk_cell_renderer_text_new(); | ||
166 | |||
167 | col_idx = 0; | ||
168 | |||
169 | perf_hpp__for_each_format(fmt) { | ||
170 | fmt->header(&hpp); | ||
171 | |||
172 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
173 | -1, ltrim(s), | ||
174 | renderer, "markup", | ||
175 | col_idx++, NULL); | ||
176 | } | ||
177 | |||
178 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
179 | if (se->elide) | ||
180 | continue; | ||
181 | |||
182 | gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), | ||
183 | -1, se->se_header, | ||
184 | renderer, "text", | ||
185 | col_idx++, NULL); | ||
186 | } | ||
187 | |||
188 | gtk_tree_view_set_model(GTK_TREE_VIEW(view), GTK_TREE_MODEL(store)); | ||
189 | |||
190 | g_object_unref(GTK_TREE_MODEL(store)); | ||
191 | |||
192 | for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { | ||
193 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | ||
194 | GtkTreeIter iter; | ||
195 | |||
196 | if (h->filtered) | ||
197 | continue; | ||
198 | |||
199 | gtk_list_store_append(store, &iter); | ||
200 | |||
201 | col_idx = 0; | ||
202 | |||
203 | perf_hpp__for_each_format(fmt) { | ||
204 | if (fmt->color) | ||
205 | fmt->color(&hpp, h); | ||
206 | else | ||
207 | fmt->entry(&hpp, h); | ||
208 | |||
209 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | ||
210 | } | ||
211 | |||
212 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
213 | if (se->elide) | ||
214 | continue; | ||
215 | |||
216 | se->se_snprintf(h, s, ARRAY_SIZE(s), | ||
217 | hists__col_len(hists, se->se_width_idx)); | ||
218 | |||
219 | gtk_list_store_set(store, &iter, col_idx++, s, -1); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | gtk_container_add(GTK_CONTAINER(window), view); | ||
224 | } | ||
225 | |||
226 | int perf_evlist__gtk_browse_hists(struct perf_evlist *evlist, | ||
227 | const char *help, | ||
228 | struct hist_browser_timer *hbt __maybe_unused) | ||
229 | { | ||
230 | struct perf_evsel *pos; | ||
231 | GtkWidget *vbox; | ||
232 | GtkWidget *notebook; | ||
233 | GtkWidget *info_bar; | ||
234 | GtkWidget *statbar; | ||
235 | GtkWidget *window; | ||
236 | |||
237 | signal(SIGSEGV, perf_gtk__signal); | ||
238 | signal(SIGFPE, perf_gtk__signal); | ||
239 | signal(SIGINT, perf_gtk__signal); | ||
240 | signal(SIGQUIT, perf_gtk__signal); | ||
241 | signal(SIGTERM, perf_gtk__signal); | ||
242 | |||
243 | window = gtk_window_new(GTK_WINDOW_TOPLEVEL); | ||
244 | |||
245 | gtk_window_set_title(GTK_WINDOW(window), "perf report"); | ||
246 | |||
247 | g_signal_connect(window, "delete_event", gtk_main_quit, NULL); | ||
248 | |||
249 | pgctx = perf_gtk__activate_context(window); | ||
250 | if (!pgctx) | ||
251 | return -1; | ||
252 | |||
253 | vbox = gtk_vbox_new(FALSE, 0); | ||
254 | |||
255 | notebook = gtk_notebook_new(); | ||
256 | |||
257 | gtk_box_pack_start(GTK_BOX(vbox), notebook, TRUE, TRUE, 0); | ||
258 | |||
259 | info_bar = perf_gtk__setup_info_bar(); | ||
260 | if (info_bar) | ||
261 | gtk_box_pack_start(GTK_BOX(vbox), info_bar, FALSE, FALSE, 0); | ||
262 | |||
263 | statbar = perf_gtk__setup_statusbar(); | ||
264 | gtk_box_pack_start(GTK_BOX(vbox), statbar, FALSE, FALSE, 0); | ||
265 | |||
266 | gtk_container_add(GTK_CONTAINER(window), vbox); | ||
267 | |||
268 | list_for_each_entry(pos, &evlist->entries, node) { | ||
269 | struct hists *hists = &pos->hists; | ||
270 | const char *evname = perf_evsel__name(pos); | ||
271 | GtkWidget *scrolled_window; | ||
272 | GtkWidget *tab_label; | ||
273 | char buf[512]; | ||
274 | size_t size = sizeof(buf); | ||
275 | |||
276 | if (symbol_conf.event_group) { | ||
277 | if (!perf_evsel__is_group_leader(pos)) | ||
278 | continue; | ||
279 | |||
280 | if (pos->nr_members > 1) { | ||
281 | perf_evsel__group_desc(pos, buf, size); | ||
282 | evname = buf; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | scrolled_window = gtk_scrolled_window_new(NULL, NULL); | ||
287 | |||
288 | gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_window), | ||
289 | GTK_POLICY_AUTOMATIC, | ||
290 | GTK_POLICY_AUTOMATIC); | ||
291 | |||
292 | perf_gtk__show_hists(scrolled_window, hists); | ||
293 | |||
294 | tab_label = gtk_label_new(evname); | ||
295 | |||
296 | gtk_notebook_append_page(GTK_NOTEBOOK(notebook), scrolled_window, tab_label); | ||
297 | } | ||
298 | |||
299 | gtk_widget_show_all(window); | ||
300 | |||
301 | perf_gtk__resize_window(window); | ||
302 | |||
303 | gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER); | ||
304 | |||
305 | ui_helpline__push(help); | ||
306 | |||
307 | gtk_main(); | ||
308 | |||
309 | perf_gtk__deactivate_context(&pgctx); | ||
310 | |||
311 | return 0; | ||
312 | } | ||
diff --git a/tools/perf/ui/helpline.c b/tools/perf/ui/helpline.c index a49bcf3c190b..700fb3cfa1c7 100644 --- a/tools/perf/ui/helpline.c +++ b/tools/perf/ui/helpline.c | |||
@@ -16,9 +16,16 @@ static void nop_helpline__push(const char *msg __maybe_unused) | |||
16 | { | 16 | { |
17 | } | 17 | } |
18 | 18 | ||
19 | static int nop_helpline__show(const char *fmt __maybe_unused, | ||
20 | va_list ap __maybe_unused) | ||
21 | { | ||
22 | return 0; | ||
23 | } | ||
24 | |||
19 | static struct ui_helpline default_helpline_fns = { | 25 | static struct ui_helpline default_helpline_fns = { |
20 | .pop = nop_helpline__pop, | 26 | .pop = nop_helpline__pop, |
21 | .push = nop_helpline__push, | 27 | .push = nop_helpline__push, |
28 | .show = nop_helpline__show, | ||
22 | }; | 29 | }; |
23 | 30 | ||
24 | struct ui_helpline *helpline_fns = &default_helpline_fns; | 31 | struct ui_helpline *helpline_fns = &default_helpline_fns; |
@@ -59,3 +66,8 @@ void ui_helpline__puts(const char *msg) | |||
59 | ui_helpline__pop(); | 66 | ui_helpline__pop(); |
60 | ui_helpline__push(msg); | 67 | ui_helpline__push(msg); |
61 | } | 68 | } |
69 | |||
70 | int ui_helpline__vshow(const char *fmt, va_list ap) | ||
71 | { | ||
72 | return helpline_fns->show(fmt, ap); | ||
73 | } | ||
diff --git a/tools/perf/ui/helpline.h b/tools/perf/ui/helpline.h index baa28a4d16b9..46181f4fc07e 100644 --- a/tools/perf/ui/helpline.h +++ b/tools/perf/ui/helpline.h | |||
@@ -9,6 +9,7 @@ | |||
9 | struct ui_helpline { | 9 | struct ui_helpline { |
10 | void (*pop)(void); | 10 | void (*pop)(void); |
11 | void (*push)(const char *msg); | 11 | void (*push)(const char *msg); |
12 | int (*show)(const char *fmt, va_list ap); | ||
12 | }; | 13 | }; |
13 | 14 | ||
14 | extern struct ui_helpline *helpline_fns; | 15 | extern struct ui_helpline *helpline_fns; |
@@ -20,28 +21,9 @@ void ui_helpline__push(const char *msg); | |||
20 | void ui_helpline__vpush(const char *fmt, va_list ap); | 21 | void ui_helpline__vpush(const char *fmt, va_list ap); |
21 | void ui_helpline__fpush(const char *fmt, ...); | 22 | void ui_helpline__fpush(const char *fmt, ...); |
22 | void ui_helpline__puts(const char *msg); | 23 | void ui_helpline__puts(const char *msg); |
24 | int ui_helpline__vshow(const char *fmt, va_list ap); | ||
23 | 25 | ||
24 | extern char ui_helpline__current[512]; | 26 | extern char ui_helpline__current[512]; |
25 | |||
26 | #ifdef NEWT_SUPPORT | ||
27 | extern char ui_helpline__last_msg[]; | 27 | extern char ui_helpline__last_msg[]; |
28 | int ui_helpline__show_help(const char *format, va_list ap); | ||
29 | #else | ||
30 | static inline int ui_helpline__show_help(const char *format __maybe_unused, | ||
31 | va_list ap __maybe_unused) | ||
32 | { | ||
33 | return 0; | ||
34 | } | ||
35 | #endif /* NEWT_SUPPORT */ | ||
36 | |||
37 | #ifdef GTK2_SUPPORT | ||
38 | int perf_gtk__show_helpline(const char *format, va_list ap); | ||
39 | #else | ||
40 | static inline int perf_gtk__show_helpline(const char *format __maybe_unused, | ||
41 | va_list ap __maybe_unused) | ||
42 | { | ||
43 | return 0; | ||
44 | } | ||
45 | #endif /* GTK2_SUPPORT */ | ||
46 | 28 | ||
47 | #endif /* _PERF_UI_HELPLINE_H_ */ | 29 | #endif /* _PERF_UI_HELPLINE_H_ */ |
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c index aa84130024d5..d671e63aa351 100644 --- a/tools/perf/ui/hist.c +++ b/tools/perf/ui/hist.c | |||
@@ -3,151 +3,163 @@ | |||
3 | #include "../util/hist.h" | 3 | #include "../util/hist.h" |
4 | #include "../util/util.h" | 4 | #include "../util/util.h" |
5 | #include "../util/sort.h" | 5 | #include "../util/sort.h" |
6 | 6 | #include "../util/evsel.h" | |
7 | 7 | ||
8 | /* hist period print (hpp) functions */ | 8 | /* hist period print (hpp) functions */ |
9 | static int hpp__header_overhead(struct perf_hpp *hpp) | ||
10 | { | ||
11 | return scnprintf(hpp->buf, hpp->size, "Overhead"); | ||
12 | } | ||
13 | |||
14 | static int hpp__width_overhead(struct perf_hpp *hpp __maybe_unused) | ||
15 | { | ||
16 | return 8; | ||
17 | } | ||
18 | |||
19 | static int hpp__color_overhead(struct perf_hpp *hpp, struct hist_entry *he) | ||
20 | { | ||
21 | struct hists *hists = he->hists; | ||
22 | double percent = 100.0 * he->stat.period / hists->stats.total_period; | ||
23 | 9 | ||
24 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); | 10 | typedef int (*hpp_snprint_fn)(char *buf, size_t size, const char *fmt, ...); |
25 | } | ||
26 | 11 | ||
27 | static int hpp__entry_overhead(struct perf_hpp *hpp, struct hist_entry *he) | 12 | static int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, |
13 | u64 (*get_field)(struct hist_entry *), | ||
14 | const char *fmt, hpp_snprint_fn print_fn, | ||
15 | bool fmt_percent) | ||
28 | { | 16 | { |
17 | int ret; | ||
29 | struct hists *hists = he->hists; | 18 | struct hists *hists = he->hists; |
30 | double percent = 100.0 * he->stat.period / hists->stats.total_period; | ||
31 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%%"; | ||
32 | |||
33 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | ||
34 | } | ||
35 | 19 | ||
36 | static int hpp__header_overhead_sys(struct perf_hpp *hpp) | 20 | if (fmt_percent) { |
37 | { | 21 | double percent = 0.0; |
38 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; | ||
39 | |||
40 | return scnprintf(hpp->buf, hpp->size, fmt, "sys"); | ||
41 | } | ||
42 | 22 | ||
43 | static int hpp__width_overhead_sys(struct perf_hpp *hpp __maybe_unused) | 23 | if (hists->stats.total_period) |
44 | { | 24 | percent = 100.0 * get_field(he) / |
45 | return 7; | 25 | hists->stats.total_period; |
46 | } | ||
47 | 26 | ||
48 | static int hpp__color_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) | 27 | ret = print_fn(hpp->buf, hpp->size, fmt, percent); |
49 | { | 28 | } else |
50 | struct hists *hists = he->hists; | 29 | ret = print_fn(hpp->buf, hpp->size, fmt, get_field(he)); |
51 | double percent = 100.0 * he->stat.period_sys / hists->stats.total_period; | ||
52 | 30 | ||
53 | return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); | 31 | if (symbol_conf.event_group) { |
54 | } | 32 | int prev_idx, idx_delta; |
33 | struct perf_evsel *evsel = hists_to_evsel(hists); | ||
34 | struct hist_entry *pair; | ||
35 | int nr_members = evsel->nr_members; | ||
55 | 36 | ||
56 | static int hpp__entry_overhead_sys(struct perf_hpp *hpp, struct hist_entry *he) | 37 | if (nr_members <= 1) |
57 | { | 38 | return ret; |
58 | struct hists *hists = he->hists; | ||
59 | double percent = 100.0 * he->stat.period_sys / hists->stats.total_period; | ||
60 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; | ||
61 | 39 | ||
62 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | 40 | prev_idx = perf_evsel__group_idx(evsel); |
63 | } | ||
64 | 41 | ||
65 | static int hpp__header_overhead_us(struct perf_hpp *hpp) | 42 | list_for_each_entry(pair, &he->pairs.head, pairs.node) { |
66 | { | 43 | u64 period = get_field(pair); |
67 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; | 44 | u64 total = pair->hists->stats.total_period; |
68 | 45 | ||
69 | return scnprintf(hpp->buf, hpp->size, fmt, "user"); | 46 | if (!total) |
70 | } | 47 | continue; |
71 | 48 | ||
72 | static int hpp__width_overhead_us(struct perf_hpp *hpp __maybe_unused) | 49 | evsel = hists_to_evsel(pair->hists); |
73 | { | 50 | idx_delta = perf_evsel__group_idx(evsel) - prev_idx - 1; |
74 | return 7; | ||
75 | } | ||
76 | 51 | ||
77 | static int hpp__color_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) | 52 | while (idx_delta--) { |
78 | { | 53 | /* |
79 | struct hists *hists = he->hists; | 54 | * zero-fill group members in the middle which |
80 | double percent = 100.0 * he->stat.period_us / hists->stats.total_period; | 55 | * have no sample |
56 | */ | ||
57 | ret += print_fn(hpp->buf + ret, hpp->size - ret, | ||
58 | fmt, 0); | ||
59 | } | ||
81 | 60 | ||
82 | return percent_color_snprintf(hpp->buf, hpp->size, "%6.2f%%", percent); | 61 | if (fmt_percent) |
83 | } | 62 | ret += print_fn(hpp->buf + ret, hpp->size - ret, |
63 | fmt, 100.0 * period / total); | ||
64 | else | ||
65 | ret += print_fn(hpp->buf + ret, hpp->size - ret, | ||
66 | fmt, period); | ||
84 | 67 | ||
85 | static int hpp__entry_overhead_us(struct perf_hpp *hpp, struct hist_entry *he) | 68 | prev_idx = perf_evsel__group_idx(evsel); |
86 | { | 69 | } |
87 | struct hists *hists = he->hists; | ||
88 | double percent = 100.0 * he->stat.period_us / hists->stats.total_period; | ||
89 | const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%"; | ||
90 | |||
91 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | ||
92 | } | ||
93 | |||
94 | static int hpp__header_overhead_guest_sys(struct perf_hpp *hpp) | ||
95 | { | ||
96 | return scnprintf(hpp->buf, hpp->size, "guest sys"); | ||
97 | } | ||
98 | |||
99 | static int hpp__width_overhead_guest_sys(struct perf_hpp *hpp __maybe_unused) | ||
100 | { | ||
101 | return 9; | ||
102 | } | ||
103 | |||
104 | static int hpp__color_overhead_guest_sys(struct perf_hpp *hpp, | ||
105 | struct hist_entry *he) | ||
106 | { | ||
107 | struct hists *hists = he->hists; | ||
108 | double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period; | ||
109 | |||
110 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); | ||
111 | } | ||
112 | |||
113 | static int hpp__entry_overhead_guest_sys(struct perf_hpp *hpp, | ||
114 | struct hist_entry *he) | ||
115 | { | ||
116 | struct hists *hists = he->hists; | ||
117 | double percent = 100.0 * he->stat.period_guest_sys / hists->stats.total_period; | ||
118 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; | ||
119 | |||
120 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | ||
121 | } | ||
122 | |||
123 | static int hpp__header_overhead_guest_us(struct perf_hpp *hpp) | ||
124 | { | ||
125 | return scnprintf(hpp->buf, hpp->size, "guest usr"); | ||
126 | } | ||
127 | 70 | ||
128 | static int hpp__width_overhead_guest_us(struct perf_hpp *hpp __maybe_unused) | 71 | idx_delta = nr_members - prev_idx - 1; |
129 | { | ||
130 | return 9; | ||
131 | } | ||
132 | 72 | ||
133 | static int hpp__color_overhead_guest_us(struct perf_hpp *hpp, | 73 | while (idx_delta--) { |
134 | struct hist_entry *he) | 74 | /* |
135 | { | 75 | * zero-fill group members at last which have no sample |
136 | struct hists *hists = he->hists; | 76 | */ |
137 | double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; | 77 | ret += print_fn(hpp->buf + ret, hpp->size - ret, |
138 | 78 | fmt, 0); | |
139 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%% ", percent); | 79 | } |
80 | } | ||
81 | return ret; | ||
140 | } | 82 | } |
141 | 83 | ||
142 | static int hpp__entry_overhead_guest_us(struct perf_hpp *hpp, | 84 | #define __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ |
143 | struct hist_entry *he) | 85 | static int hpp__header_##_type(struct perf_hpp *hpp) \ |
144 | { | 86 | { \ |
145 | struct hists *hists = he->hists; | 87 | int len = _min_width; \ |
146 | double percent = 100.0 * he->stat.period_guest_us / hists->stats.total_period; | 88 | \ |
147 | const char *fmt = symbol_conf.field_sep ? "%.2f" : " %6.2f%% "; | 89 | if (symbol_conf.event_group) { \ |
90 | struct perf_evsel *evsel = hpp->ptr; \ | ||
91 | \ | ||
92 | len = max(len, evsel->nr_members * _unit_width); \ | ||
93 | } \ | ||
94 | return scnprintf(hpp->buf, hpp->size, "%*s", len, _str); \ | ||
95 | } | ||
96 | |||
97 | #define __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | ||
98 | static int hpp__width_##_type(struct perf_hpp *hpp __maybe_unused) \ | ||
99 | { \ | ||
100 | int len = _min_width; \ | ||
101 | \ | ||
102 | if (symbol_conf.event_group) { \ | ||
103 | struct perf_evsel *evsel = hpp->ptr; \ | ||
104 | \ | ||
105 | len = max(len, evsel->nr_members * _unit_width); \ | ||
106 | } \ | ||
107 | return len; \ | ||
108 | } | ||
109 | |||
110 | #define __HPP_COLOR_PERCENT_FN(_type, _field) \ | ||
111 | static u64 he_get_##_field(struct hist_entry *he) \ | ||
112 | { \ | ||
113 | return he->stat._field; \ | ||
114 | } \ | ||
115 | \ | ||
116 | static int hpp__color_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | ||
117 | { \ | ||
118 | return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \ | ||
119 | (hpp_snprint_fn)percent_color_snprintf, true); \ | ||
120 | } | ||
121 | |||
122 | #define __HPP_ENTRY_PERCENT_FN(_type, _field) \ | ||
123 | static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | ||
124 | { \ | ||
125 | const char *fmt = symbol_conf.field_sep ? " %.2f" : " %6.2f%%"; \ | ||
126 | return __hpp__fmt(hpp, he, he_get_##_field, fmt, \ | ||
127 | scnprintf, true); \ | ||
128 | } | ||
129 | |||
130 | #define __HPP_ENTRY_RAW_FN(_type, _field) \ | ||
131 | static u64 he_get_raw_##_field(struct hist_entry *he) \ | ||
132 | { \ | ||
133 | return he->stat._field; \ | ||
134 | } \ | ||
135 | \ | ||
136 | static int hpp__entry_##_type(struct perf_hpp *hpp, struct hist_entry *he) \ | ||
137 | { \ | ||
138 | const char *fmt = symbol_conf.field_sep ? " %"PRIu64 : " %11"PRIu64; \ | ||
139 | return __hpp__fmt(hpp, he, he_get_raw_##_field, fmt, scnprintf, false); \ | ||
140 | } | ||
141 | |||
142 | #define HPP_PERCENT_FNS(_type, _str, _field, _min_width, _unit_width) \ | ||
143 | __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | ||
144 | __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | ||
145 | __HPP_COLOR_PERCENT_FN(_type, _field) \ | ||
146 | __HPP_ENTRY_PERCENT_FN(_type, _field) | ||
147 | |||
148 | #define HPP_RAW_FNS(_type, _str, _field, _min_width, _unit_width) \ | ||
149 | __HPP_HEADER_FN(_type, _str, _min_width, _unit_width) \ | ||
150 | __HPP_WIDTH_FN(_type, _min_width, _unit_width) \ | ||
151 | __HPP_ENTRY_RAW_FN(_type, _field) | ||
152 | |||
153 | |||
154 | HPP_PERCENT_FNS(overhead, "Overhead", period, 8, 8) | ||
155 | HPP_PERCENT_FNS(overhead_sys, "sys", period_sys, 8, 8) | ||
156 | HPP_PERCENT_FNS(overhead_us, "usr", period_us, 8, 8) | ||
157 | HPP_PERCENT_FNS(overhead_guest_sys, "guest sys", period_guest_sys, 9, 8) | ||
158 | HPP_PERCENT_FNS(overhead_guest_us, "guest usr", period_guest_us, 9, 8) | ||
159 | |||
160 | HPP_RAW_FNS(samples, "Samples", nr_events, 12, 12) | ||
161 | HPP_RAW_FNS(period, "Period", period, 12, 12) | ||
148 | 162 | ||
149 | return scnprintf(hpp->buf, hpp->size, fmt, percent); | ||
150 | } | ||
151 | 163 | ||
152 | static int hpp__header_baseline(struct perf_hpp *hpp) | 164 | static int hpp__header_baseline(struct perf_hpp *hpp) |
153 | { | 165 | { |
@@ -179,7 +191,7 @@ static int hpp__color_baseline(struct perf_hpp *hpp, struct hist_entry *he) | |||
179 | { | 191 | { |
180 | double percent = baseline_percent(he); | 192 | double percent = baseline_percent(he); |
181 | 193 | ||
182 | if (hist_entry__has_pairs(he)) | 194 | if (hist_entry__has_pairs(he) || symbol_conf.field_sep) |
183 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); | 195 | return percent_color_snprintf(hpp->buf, hpp->size, " %6.2f%%", percent); |
184 | else | 196 | else |
185 | return scnprintf(hpp->buf, hpp->size, " "); | 197 | return scnprintf(hpp->buf, hpp->size, " "); |
@@ -196,44 +208,6 @@ static int hpp__entry_baseline(struct perf_hpp *hpp, struct hist_entry *he) | |||
196 | return scnprintf(hpp->buf, hpp->size, " "); | 208 | return scnprintf(hpp->buf, hpp->size, " "); |
197 | } | 209 | } |
198 | 210 | ||
199 | static int hpp__header_samples(struct perf_hpp *hpp) | ||
200 | { | ||
201 | const char *fmt = symbol_conf.field_sep ? "%s" : "%11s"; | ||
202 | |||
203 | return scnprintf(hpp->buf, hpp->size, fmt, "Samples"); | ||
204 | } | ||
205 | |||
206 | static int hpp__width_samples(struct perf_hpp *hpp __maybe_unused) | ||
207 | { | ||
208 | return 11; | ||
209 | } | ||
210 | |||
211 | static int hpp__entry_samples(struct perf_hpp *hpp, struct hist_entry *he) | ||
212 | { | ||
213 | const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%11" PRIu64; | ||
214 | |||
215 | return scnprintf(hpp->buf, hpp->size, fmt, he->stat.nr_events); | ||
216 | } | ||
217 | |||
218 | static int hpp__header_period(struct perf_hpp *hpp) | ||
219 | { | ||
220 | const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; | ||
221 | |||
222 | return scnprintf(hpp->buf, hpp->size, fmt, "Period"); | ||
223 | } | ||
224 | |||
225 | static int hpp__width_period(struct perf_hpp *hpp __maybe_unused) | ||
226 | { | ||
227 | return 12; | ||
228 | } | ||
229 | |||
230 | static int hpp__entry_period(struct perf_hpp *hpp, struct hist_entry *he) | ||
231 | { | ||
232 | const char *fmt = symbol_conf.field_sep ? "%" PRIu64 : "%12" PRIu64; | ||
233 | |||
234 | return scnprintf(hpp->buf, hpp->size, fmt, he->stat.period); | ||
235 | } | ||
236 | |||
237 | static int hpp__header_period_baseline(struct perf_hpp *hpp) | 211 | static int hpp__header_period_baseline(struct perf_hpp *hpp) |
238 | { | 212 | { |
239 | const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; | 213 | const char *fmt = symbol_conf.field_sep ? "%s" : "%12s"; |
@@ -254,6 +228,7 @@ static int hpp__entry_period_baseline(struct perf_hpp *hpp, struct hist_entry *h | |||
254 | 228 | ||
255 | return scnprintf(hpp->buf, hpp->size, fmt, period); | 229 | return scnprintf(hpp->buf, hpp->size, fmt, period); |
256 | } | 230 | } |
231 | |||
257 | static int hpp__header_delta(struct perf_hpp *hpp) | 232 | static int hpp__header_delta(struct perf_hpp *hpp) |
258 | { | 233 | { |
259 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; | 234 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7s"; |
@@ -268,14 +243,18 @@ static int hpp__width_delta(struct perf_hpp *hpp __maybe_unused) | |||
268 | 243 | ||
269 | static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) | 244 | static int hpp__entry_delta(struct perf_hpp *hpp, struct hist_entry *he) |
270 | { | 245 | { |
246 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
271 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; | 247 | const char *fmt = symbol_conf.field_sep ? "%s" : "%7.7s"; |
272 | char buf[32] = " "; | 248 | char buf[32] = " "; |
273 | double diff; | 249 | double diff = 0.0; |
274 | 250 | ||
275 | if (he->diff.computed) | 251 | if (pair) { |
276 | diff = he->diff.period_ratio_delta; | 252 | if (he->diff.computed) |
277 | else | 253 | diff = he->diff.period_ratio_delta; |
278 | diff = perf_diff__compute_delta(he); | 254 | else |
255 | diff = perf_diff__compute_delta(he, pair); | ||
256 | } else | ||
257 | diff = perf_diff__period_percent(he, he->stat.period); | ||
279 | 258 | ||
280 | if (fabs(diff) >= 0.01) | 259 | if (fabs(diff) >= 0.01) |
281 | scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); | 260 | scnprintf(buf, sizeof(buf), "%+4.2F%%", diff); |
@@ -297,14 +276,17 @@ static int hpp__width_ratio(struct perf_hpp *hpp __maybe_unused) | |||
297 | 276 | ||
298 | static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) | 277 | static int hpp__entry_ratio(struct perf_hpp *hpp, struct hist_entry *he) |
299 | { | 278 | { |
279 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
300 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; | 280 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; |
301 | char buf[32] = " "; | 281 | char buf[32] = " "; |
302 | double ratio; | 282 | double ratio = 0.0; |
303 | 283 | ||
304 | if (he->diff.computed) | 284 | if (pair) { |
305 | ratio = he->diff.period_ratio; | 285 | if (he->diff.computed) |
306 | else | 286 | ratio = he->diff.period_ratio; |
307 | ratio = perf_diff__compute_ratio(he); | 287 | else |
288 | ratio = perf_diff__compute_ratio(he, pair); | ||
289 | } | ||
308 | 290 | ||
309 | if (ratio > 0.0) | 291 | if (ratio > 0.0) |
310 | scnprintf(buf, sizeof(buf), "%+14.6F", ratio); | 292 | scnprintf(buf, sizeof(buf), "%+14.6F", ratio); |
@@ -326,14 +308,17 @@ static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused) | |||
326 | 308 | ||
327 | static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) | 309 | static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) |
328 | { | 310 | { |
311 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
329 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; | 312 | const char *fmt = symbol_conf.field_sep ? "%s" : "%14s"; |
330 | char buf[32] = " "; | 313 | char buf[32] = " "; |
331 | s64 wdiff; | 314 | s64 wdiff = 0; |
332 | 315 | ||
333 | if (he->diff.computed) | 316 | if (pair) { |
334 | wdiff = he->diff.wdiff; | 317 | if (he->diff.computed) |
335 | else | 318 | wdiff = he->diff.wdiff; |
336 | wdiff = perf_diff__compute_wdiff(he); | 319 | else |
320 | wdiff = perf_diff__compute_wdiff(he, pair); | ||
321 | } | ||
337 | 322 | ||
338 | if (wdiff != 0) | 323 | if (wdiff != 0) |
339 | scnprintf(buf, sizeof(buf), "%14ld", wdiff); | 324 | scnprintf(buf, sizeof(buf), "%14ld", wdiff); |
@@ -341,30 +326,6 @@ static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he) | |||
341 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | 326 | return scnprintf(hpp->buf, hpp->size, fmt, buf); |
342 | } | 327 | } |
343 | 328 | ||
344 | static int hpp__header_displ(struct perf_hpp *hpp) | ||
345 | { | ||
346 | return scnprintf(hpp->buf, hpp->size, "Displ."); | ||
347 | } | ||
348 | |||
349 | static int hpp__width_displ(struct perf_hpp *hpp __maybe_unused) | ||
350 | { | ||
351 | return 6; | ||
352 | } | ||
353 | |||
354 | static int hpp__entry_displ(struct perf_hpp *hpp, | ||
355 | struct hist_entry *he) | ||
356 | { | ||
357 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
358 | long displacement = pair ? pair->position - he->position : 0; | ||
359 | const char *fmt = symbol_conf.field_sep ? "%s" : "%6.6s"; | ||
360 | char buf[32] = " "; | ||
361 | |||
362 | if (displacement) | ||
363 | scnprintf(buf, sizeof(buf), "%+4ld", displacement); | ||
364 | |||
365 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | ||
366 | } | ||
367 | |||
368 | static int hpp__header_formula(struct perf_hpp *hpp) | 329 | static int hpp__header_formula(struct perf_hpp *hpp) |
369 | { | 330 | { |
370 | const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; | 331 | const char *fmt = symbol_conf.field_sep ? "%s" : "%70s"; |
@@ -379,67 +340,91 @@ static int hpp__width_formula(struct perf_hpp *hpp __maybe_unused) | |||
379 | 340 | ||
380 | static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) | 341 | static int hpp__entry_formula(struct perf_hpp *hpp, struct hist_entry *he) |
381 | { | 342 | { |
343 | struct hist_entry *pair = hist_entry__next_pair(he); | ||
382 | const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; | 344 | const char *fmt = symbol_conf.field_sep ? "%s" : "%-70s"; |
383 | char buf[96] = " "; | 345 | char buf[96] = " "; |
384 | 346 | ||
385 | perf_diff__formula(buf, sizeof(buf), he); | 347 | if (pair) |
348 | perf_diff__formula(he, pair, buf, sizeof(buf)); | ||
349 | |||
386 | return scnprintf(hpp->buf, hpp->size, fmt, buf); | 350 | return scnprintf(hpp->buf, hpp->size, fmt, buf); |
387 | } | 351 | } |
388 | 352 | ||
389 | #define HPP__COLOR_PRINT_FNS(_name) \ | 353 | #define HPP__COLOR_PRINT_FNS(_name) \ |
390 | .header = hpp__header_ ## _name, \ | 354 | { \ |
391 | .width = hpp__width_ ## _name, \ | 355 | .header = hpp__header_ ## _name, \ |
392 | .color = hpp__color_ ## _name, \ | 356 | .width = hpp__width_ ## _name, \ |
393 | .entry = hpp__entry_ ## _name | 357 | .color = hpp__color_ ## _name, \ |
358 | .entry = hpp__entry_ ## _name \ | ||
359 | } | ||
394 | 360 | ||
395 | #define HPP__PRINT_FNS(_name) \ | 361 | #define HPP__PRINT_FNS(_name) \ |
396 | .header = hpp__header_ ## _name, \ | 362 | { \ |
397 | .width = hpp__width_ ## _name, \ | 363 | .header = hpp__header_ ## _name, \ |
398 | .entry = hpp__entry_ ## _name | 364 | .width = hpp__width_ ## _name, \ |
365 | .entry = hpp__entry_ ## _name \ | ||
366 | } | ||
399 | 367 | ||
400 | struct perf_hpp_fmt perf_hpp__format[] = { | 368 | struct perf_hpp_fmt perf_hpp__format[] = { |
401 | { .cond = false, HPP__COLOR_PRINT_FNS(baseline) }, | 369 | HPP__COLOR_PRINT_FNS(baseline), |
402 | { .cond = true, HPP__COLOR_PRINT_FNS(overhead) }, | 370 | HPP__COLOR_PRINT_FNS(overhead), |
403 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_sys) }, | 371 | HPP__COLOR_PRINT_FNS(overhead_sys), |
404 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_us) }, | 372 | HPP__COLOR_PRINT_FNS(overhead_us), |
405 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_sys) }, | 373 | HPP__COLOR_PRINT_FNS(overhead_guest_sys), |
406 | { .cond = false, HPP__COLOR_PRINT_FNS(overhead_guest_us) }, | 374 | HPP__COLOR_PRINT_FNS(overhead_guest_us), |
407 | { .cond = false, HPP__PRINT_FNS(samples) }, | 375 | HPP__PRINT_FNS(samples), |
408 | { .cond = false, HPP__PRINT_FNS(period) }, | 376 | HPP__PRINT_FNS(period), |
409 | { .cond = false, HPP__PRINT_FNS(period_baseline) }, | 377 | HPP__PRINT_FNS(period_baseline), |
410 | { .cond = false, HPP__PRINT_FNS(delta) }, | 378 | HPP__PRINT_FNS(delta), |
411 | { .cond = false, HPP__PRINT_FNS(ratio) }, | 379 | HPP__PRINT_FNS(ratio), |
412 | { .cond = false, HPP__PRINT_FNS(wdiff) }, | 380 | HPP__PRINT_FNS(wdiff), |
413 | { .cond = false, HPP__PRINT_FNS(displ) }, | 381 | HPP__PRINT_FNS(formula) |
414 | { .cond = false, HPP__PRINT_FNS(formula) } | ||
415 | }; | 382 | }; |
416 | 383 | ||
384 | LIST_HEAD(perf_hpp__list); | ||
385 | |||
386 | |||
417 | #undef HPP__COLOR_PRINT_FNS | 387 | #undef HPP__COLOR_PRINT_FNS |
418 | #undef HPP__PRINT_FNS | 388 | #undef HPP__PRINT_FNS |
419 | 389 | ||
390 | #undef HPP_PERCENT_FNS | ||
391 | #undef HPP_RAW_FNS | ||
392 | |||
393 | #undef __HPP_HEADER_FN | ||
394 | #undef __HPP_WIDTH_FN | ||
395 | #undef __HPP_COLOR_PERCENT_FN | ||
396 | #undef __HPP_ENTRY_PERCENT_FN | ||
397 | #undef __HPP_ENTRY_RAW_FN | ||
398 | |||
399 | |||
420 | void perf_hpp__init(void) | 400 | void perf_hpp__init(void) |
421 | { | 401 | { |
422 | if (symbol_conf.show_cpu_utilization) { | 402 | if (symbol_conf.show_cpu_utilization) { |
423 | perf_hpp__format[PERF_HPP__OVERHEAD_SYS].cond = true; | 403 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_SYS); |
424 | perf_hpp__format[PERF_HPP__OVERHEAD_US].cond = true; | 404 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_US); |
425 | 405 | ||
426 | if (perf_guest) { | 406 | if (perf_guest) { |
427 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_SYS].cond = true; | 407 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_SYS); |
428 | perf_hpp__format[PERF_HPP__OVERHEAD_GUEST_US].cond = true; | 408 | perf_hpp__column_enable(PERF_HPP__OVERHEAD_GUEST_US); |
429 | } | 409 | } |
430 | } | 410 | } |
431 | 411 | ||
432 | if (symbol_conf.show_nr_samples) | 412 | if (symbol_conf.show_nr_samples) |
433 | perf_hpp__format[PERF_HPP__SAMPLES].cond = true; | 413 | perf_hpp__column_enable(PERF_HPP__SAMPLES); |
434 | 414 | ||
435 | if (symbol_conf.show_total_period) | 415 | if (symbol_conf.show_total_period) |
436 | perf_hpp__format[PERF_HPP__PERIOD].cond = true; | 416 | perf_hpp__column_enable(PERF_HPP__PERIOD); |
417 | } | ||
418 | |||
419 | void perf_hpp__column_register(struct perf_hpp_fmt *format) | ||
420 | { | ||
421 | list_add_tail(&format->list, &perf_hpp__list); | ||
437 | } | 422 | } |
438 | 423 | ||
439 | void perf_hpp__column_enable(unsigned col, bool enable) | 424 | void perf_hpp__column_enable(unsigned col) |
440 | { | 425 | { |
441 | BUG_ON(col >= PERF_HPP__MAX_INDEX); | 426 | BUG_ON(col >= PERF_HPP__MAX_INDEX); |
442 | perf_hpp__format[col].cond = enable; | 427 | perf_hpp__column_register(&perf_hpp__format[col]); |
443 | } | 428 | } |
444 | 429 | ||
445 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) | 430 | static inline void advance_hpp(struct perf_hpp *hpp, int inc) |
@@ -452,27 +437,29 @@ int hist_entry__period_snprintf(struct perf_hpp *hpp, struct hist_entry *he, | |||
452 | bool color) | 437 | bool color) |
453 | { | 438 | { |
454 | const char *sep = symbol_conf.field_sep; | 439 | const char *sep = symbol_conf.field_sep; |
440 | struct perf_hpp_fmt *fmt; | ||
455 | char *start = hpp->buf; | 441 | char *start = hpp->buf; |
456 | int i, ret; | 442 | int ret; |
457 | bool first = true; | 443 | bool first = true; |
458 | 444 | ||
459 | if (symbol_conf.exclude_other && !he->parent) | 445 | if (symbol_conf.exclude_other && !he->parent) |
460 | return 0; | 446 | return 0; |
461 | 447 | ||
462 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | 448 | perf_hpp__for_each_format(fmt) { |
463 | if (!perf_hpp__format[i].cond) | 449 | /* |
464 | continue; | 450 | * If there's no field_sep, we still need |
465 | 451 | * to display initial ' '. | |
452 | */ | ||
466 | if (!sep || !first) { | 453 | if (!sep || !first) { |
467 | ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); | 454 | ret = scnprintf(hpp->buf, hpp->size, "%s", sep ?: " "); |
468 | advance_hpp(hpp, ret); | 455 | advance_hpp(hpp, ret); |
456 | } else | ||
469 | first = false; | 457 | first = false; |
470 | } | ||
471 | 458 | ||
472 | if (color && perf_hpp__format[i].color) | 459 | if (color && fmt->color) |
473 | ret = perf_hpp__format[i].color(hpp, he); | 460 | ret = fmt->color(hpp, he); |
474 | else | 461 | else |
475 | ret = perf_hpp__format[i].entry(hpp, he); | 462 | ret = fmt->entry(hpp, he); |
476 | 463 | ||
477 | advance_hpp(hpp, ret); | 464 | advance_hpp(hpp, ret); |
478 | } | 465 | } |
@@ -504,16 +491,18 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *s, size_t size, | |||
504 | */ | 491 | */ |
505 | unsigned int hists__sort_list_width(struct hists *hists) | 492 | unsigned int hists__sort_list_width(struct hists *hists) |
506 | { | 493 | { |
494 | struct perf_hpp_fmt *fmt; | ||
507 | struct sort_entry *se; | 495 | struct sort_entry *se; |
508 | int i, ret = 0; | 496 | int i = 0, ret = 0; |
497 | struct perf_hpp dummy_hpp = { | ||
498 | .ptr = hists_to_evsel(hists), | ||
499 | }; | ||
509 | 500 | ||
510 | for (i = 0; i < PERF_HPP__MAX_INDEX; i++) { | 501 | perf_hpp__for_each_format(fmt) { |
511 | if (!perf_hpp__format[i].cond) | ||
512 | continue; | ||
513 | if (i) | 502 | if (i) |
514 | ret += 2; | 503 | ret += 2; |
515 | 504 | ||
516 | ret += perf_hpp__format[i].width(NULL); | 505 | ret += fmt->width(&dummy_hpp); |
517 | } | 506 | } |
518 | 507 | ||
519 | list_for_each_entry(se, &hist_entry__sort_list, list) | 508 | list_for_each_entry(se, &hist_entry__sort_list, list) |
diff --git a/tools/perf/ui/keysyms.h b/tools/perf/ui/keysyms.h index 809eca5707fa..65092d576b4e 100644 --- a/tools/perf/ui/keysyms.h +++ b/tools/perf/ui/keysyms.h | |||
@@ -23,5 +23,6 @@ | |||
23 | #define K_TIMER -1 | 23 | #define K_TIMER -1 |
24 | #define K_ERROR -2 | 24 | #define K_ERROR -2 |
25 | #define K_RESIZE -3 | 25 | #define K_RESIZE -3 |
26 | #define K_SWITCH_INPUT_DATA -4 | ||
26 | 27 | ||
27 | #endif /* _PERF_KEYSYMS_H_ */ | 28 | #endif /* _PERF_KEYSYMS_H_ */ |
diff --git a/tools/perf/ui/setup.c b/tools/perf/ui/setup.c index ebb4cc107876..ae6a789cb0f6 100644 --- a/tools/perf/ui/setup.c +++ b/tools/perf/ui/setup.c | |||
@@ -8,7 +8,7 @@ pthread_mutex_t ui__lock = PTHREAD_MUTEX_INITIALIZER; | |||
8 | 8 | ||
9 | void setup_browser(bool fallback_to_pager) | 9 | void setup_browser(bool fallback_to_pager) |
10 | { | 10 | { |
11 | if (!isatty(1) || dump_trace) | 11 | if (use_browser < 2 && (!isatty(1) || dump_trace)) |
12 | use_browser = 0; | 12 | use_browser = 0; |
13 | 13 | ||
14 | /* default to TUI */ | 14 | /* default to TUI */ |
@@ -30,6 +30,7 @@ void setup_browser(bool fallback_to_pager) | |||
30 | if (fallback_to_pager) | 30 | if (fallback_to_pager) |
31 | setup_pager(); | 31 | setup_pager(); |
32 | 32 | ||
33 | perf_hpp__column_enable(PERF_HPP__OVERHEAD); | ||
33 | perf_hpp__init(); | 34 | perf_hpp__init(); |
34 | break; | 35 | break; |
35 | } | 36 | } |
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c index f0ee204f99bb..ff1f60cf442e 100644 --- a/tools/perf/ui/stdio/hist.c +++ b/tools/perf/ui/stdio/hist.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include "../../util/util.h" | 3 | #include "../../util/util.h" |
4 | #include "../../util/hist.h" | 4 | #include "../../util/hist.h" |
5 | #include "../../util/sort.h" | 5 | #include "../../util/sort.h" |
6 | #include "../../util/evsel.h" | ||
6 | 7 | ||
7 | 8 | ||
8 | static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) | 9 | static size_t callchain__fprintf_left_margin(FILE *fp, int left_margin) |
@@ -335,17 +336,19 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, | |||
335 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | 336 | size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, |
336 | int max_cols, FILE *fp) | 337 | int max_cols, FILE *fp) |
337 | { | 338 | { |
339 | struct perf_hpp_fmt *fmt; | ||
338 | struct sort_entry *se; | 340 | struct sort_entry *se; |
339 | struct rb_node *nd; | 341 | struct rb_node *nd; |
340 | size_t ret = 0; | 342 | size_t ret = 0; |
341 | unsigned int width; | 343 | unsigned int width; |
342 | const char *sep = symbol_conf.field_sep; | 344 | const char *sep = symbol_conf.field_sep; |
343 | const char *col_width = symbol_conf.col_width_list_str; | 345 | const char *col_width = symbol_conf.col_width_list_str; |
344 | int idx, nr_rows = 0; | 346 | int nr_rows = 0; |
345 | char bf[96]; | 347 | char bf[96]; |
346 | struct perf_hpp dummy_hpp = { | 348 | struct perf_hpp dummy_hpp = { |
347 | .buf = bf, | 349 | .buf = bf, |
348 | .size = sizeof(bf), | 350 | .size = sizeof(bf), |
351 | .ptr = hists_to_evsel(hists), | ||
349 | }; | 352 | }; |
350 | bool first = true; | 353 | bool first = true; |
351 | 354 | ||
@@ -355,16 +358,14 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | |||
355 | goto print_entries; | 358 | goto print_entries; |
356 | 359 | ||
357 | fprintf(fp, "# "); | 360 | fprintf(fp, "# "); |
358 | for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { | ||
359 | if (!perf_hpp__format[idx].cond) | ||
360 | continue; | ||
361 | 361 | ||
362 | perf_hpp__for_each_format(fmt) { | ||
362 | if (!first) | 363 | if (!first) |
363 | fprintf(fp, "%s", sep ?: " "); | 364 | fprintf(fp, "%s", sep ?: " "); |
364 | else | 365 | else |
365 | first = false; | 366 | first = false; |
366 | 367 | ||
367 | perf_hpp__format[idx].header(&dummy_hpp); | 368 | fmt->header(&dummy_hpp); |
368 | fprintf(fp, "%s", bf); | 369 | fprintf(fp, "%s", bf); |
369 | } | 370 | } |
370 | 371 | ||
@@ -400,18 +401,16 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, | |||
400 | first = true; | 401 | first = true; |
401 | 402 | ||
402 | fprintf(fp, "# "); | 403 | fprintf(fp, "# "); |
403 | for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) { | ||
404 | unsigned int i; | ||
405 | 404 | ||
406 | if (!perf_hpp__format[idx].cond) | 405 | perf_hpp__for_each_format(fmt) { |
407 | continue; | 406 | unsigned int i; |
408 | 407 | ||
409 | if (!first) | 408 | if (!first) |
410 | fprintf(fp, "%s", sep ?: " "); | 409 | fprintf(fp, "%s", sep ?: " "); |
411 | else | 410 | else |
412 | first = false; | 411 | first = false; |
413 | 412 | ||
414 | width = perf_hpp__format[idx].width(&dummy_hpp); | 413 | width = fmt->width(&dummy_hpp); |
415 | for (i = 0; i < width; i++) | 414 | for (i = 0; i < width; i++) |
416 | fprintf(fp, "."); | 415 | fprintf(fp, "."); |
417 | } | 416 | } |
@@ -462,7 +461,7 @@ out: | |||
462 | return ret; | 461 | return ret; |
463 | } | 462 | } |
464 | 463 | ||
465 | size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) | 464 | size_t events_stats__fprintf(struct events_stats *stats, FILE *fp) |
466 | { | 465 | { |
467 | int i; | 466 | int i; |
468 | size_t ret = 0; | 467 | size_t ret = 0; |
@@ -470,7 +469,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) | |||
470 | for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { | 469 | for (i = 0; i < PERF_RECORD_HEADER_MAX; ++i) { |
471 | const char *name; | 470 | const char *name; |
472 | 471 | ||
473 | if (hists->stats.nr_events[i] == 0) | 472 | if (stats->nr_events[i] == 0) |
474 | continue; | 473 | continue; |
475 | 474 | ||
476 | name = perf_event__name(i); | 475 | name = perf_event__name(i); |
@@ -478,7 +477,7 @@ size_t hists__fprintf_nr_events(struct hists *hists, FILE *fp) | |||
478 | continue; | 477 | continue; |
479 | 478 | ||
480 | ret += fprintf(fp, "%16s events: %10d\n", name, | 479 | ret += fprintf(fp, "%16s events: %10d\n", name, |
481 | hists->stats.nr_events[i]); | 480 | stats->nr_events[i]); |
482 | } | 481 | } |
483 | 482 | ||
484 | return ret; | 483 | return ret; |
diff --git a/tools/perf/ui/tui/helpline.c b/tools/perf/ui/tui/helpline.c index 2884d2f41e33..1c8b9afd5d6e 100644 --- a/tools/perf/ui/tui/helpline.c +++ b/tools/perf/ui/tui/helpline.c | |||
@@ -8,6 +8,8 @@ | |||
8 | #include "../ui.h" | 8 | #include "../ui.h" |
9 | #include "../libslang.h" | 9 | #include "../libslang.h" |
10 | 10 | ||
11 | char ui_helpline__last_msg[1024]; | ||
12 | |||
11 | static void tui_helpline__pop(void) | 13 | static void tui_helpline__pop(void) |
12 | { | 14 | { |
13 | } | 15 | } |
@@ -23,20 +25,7 @@ static void tui_helpline__push(const char *msg) | |||
23 | strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0'; | 25 | strncpy(ui_helpline__current, msg, sz)[sz - 1] = '\0'; |
24 | } | 26 | } |
25 | 27 | ||
26 | struct ui_helpline tui_helpline_fns = { | 28 | static int tui_helpline__show(const char *format, va_list ap) |
27 | .pop = tui_helpline__pop, | ||
28 | .push = tui_helpline__push, | ||
29 | }; | ||
30 | |||
31 | void ui_helpline__init(void) | ||
32 | { | ||
33 | helpline_fns = &tui_helpline_fns; | ||
34 | ui_helpline__puts(" "); | ||
35 | } | ||
36 | |||
37 | char ui_helpline__last_msg[1024]; | ||
38 | |||
39 | int ui_helpline__show_help(const char *format, va_list ap) | ||
40 | { | 29 | { |
41 | int ret; | 30 | int ret; |
42 | static int backlog; | 31 | static int backlog; |
@@ -55,3 +44,15 @@ int ui_helpline__show_help(const char *format, va_list ap) | |||
55 | 44 | ||
56 | return ret; | 45 | return ret; |
57 | } | 46 | } |
47 | |||
48 | struct ui_helpline tui_helpline_fns = { | ||
49 | .pop = tui_helpline__pop, | ||
50 | .push = tui_helpline__push, | ||
51 | .show = tui_helpline__show, | ||
52 | }; | ||
53 | |||
54 | void ui_helpline__init(void) | ||
55 | { | ||
56 | helpline_fns = &tui_helpline_fns; | ||
57 | ui_helpline__puts(" "); | ||
58 | } | ||
diff --git a/tools/perf/ui/util.c b/tools/perf/ui/util.c index 4f989774c8c6..e3e0a963d03a 100644 --- a/tools/perf/ui/util.c +++ b/tools/perf/ui/util.c | |||
@@ -52,7 +52,6 @@ int ui__warning(const char *format, ...) | |||
52 | return ret; | 52 | return ret; |
53 | } | 53 | } |
54 | 54 | ||
55 | |||
56 | /** | 55 | /** |
57 | * perf_error__register - Register error logging functions | 56 | * perf_error__register - Register error logging functions |
58 | * @eops: The pointer to error logging function struct | 57 | * @eops: The pointer to error logging function struct |