diff options
-rw-r--r-- | tools/perf/Makefile | 4 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 35 | ||||
-rw-r--r-- | tools/perf/util/top.c | 7 | ||||
-rw-r--r-- | tools/perf/util/top.h | 15 | ||||
-rw-r--r-- | tools/perf/util/ui/browsers/top.c | 136 |
5 files changed, 189 insertions, 8 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index edc660e0bc2f..67a9f4d805de 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -621,6 +621,7 @@ else | |||
621 | LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o | 621 | LIB_OBJS += $(OUTPUT)util/ui/browsers/annotate.o |
622 | LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o | 622 | LIB_OBJS += $(OUTPUT)util/ui/browsers/hists.o |
623 | LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o | 623 | LIB_OBJS += $(OUTPUT)util/ui/browsers/map.o |
624 | LIB_OBJS += $(OUTPUT)util/ui/browsers/top.o | ||
624 | LIB_OBJS += $(OUTPUT)util/ui/helpline.o | 625 | LIB_OBJS += $(OUTPUT)util/ui/helpline.o |
625 | LIB_OBJS += $(OUTPUT)util/ui/progress.o | 626 | LIB_OBJS += $(OUTPUT)util/ui/progress.o |
626 | LIB_OBJS += $(OUTPUT)util/ui/util.o | 627 | LIB_OBJS += $(OUTPUT)util/ui/util.o |
@@ -1050,6 +1051,9 @@ $(OUTPUT)util/ui/browser.o: util/ui/browser.c $(OUTPUT)PERF-CFLAGS | |||
1050 | $(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS | 1051 | $(OUTPUT)util/ui/browsers/annotate.o: util/ui/browsers/annotate.c $(OUTPUT)PERF-CFLAGS |
1051 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< | 1052 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< |
1052 | 1053 | ||
1054 | $(OUTPUT)util/ui/browsers/top.o: util/ui/browsers/top.c $(OUTPUT)PERF-CFLAGS | ||
1055 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< | ||
1056 | |||
1053 | $(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS | 1057 | $(OUTPUT)util/ui/browsers/hists.o: util/ui/browsers/hists.c $(OUTPUT)PERF-CFLAGS |
1054 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< | 1058 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DENABLE_SLFUTURE_CONST $< |
1055 | 1059 | ||
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 3c9ba943aa48..104de9ab314c 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -20,6 +20,7 @@ | |||
20 | 20 | ||
21 | #include "perf.h" | 21 | #include "perf.h" |
22 | 22 | ||
23 | #include "util/cache.h" | ||
23 | #include "util/color.h" | 24 | #include "util/color.h" |
24 | #include "util/evlist.h" | 25 | #include "util/evlist.h" |
25 | #include "util/evsel.h" | 26 | #include "util/evsel.h" |
@@ -75,6 +76,8 @@ static struct perf_top top = { | |||
75 | 76 | ||
76 | static bool system_wide = false; | 77 | static bool system_wide = false; |
77 | 78 | ||
79 | static bool use_tui, use_stdio; | ||
80 | |||
78 | static int default_interval = 0; | 81 | static int default_interval = 0; |
79 | 82 | ||
80 | static bool inherit = false; | 83 | static bool inherit = false; |
@@ -96,11 +99,6 @@ static int sym_pcnt_filter = 5; | |||
96 | * Source functions | 99 | * Source functions |
97 | */ | 100 | */ |
98 | 101 | ||
99 | static inline struct symbol *sym_entry__symbol(struct sym_entry *self) | ||
100 | { | ||
101 | return ((void *)self) + symbol_conf.priv_size; | ||
102 | } | ||
103 | |||
104 | void get_term_dimensions(struct winsize *ws) | 102 | void get_term_dimensions(struct winsize *ws) |
105 | { | 103 | { |
106 | char *s = getenv("LINES"); | 104 | char *s = getenv("LINES"); |
@@ -695,6 +693,14 @@ static void handle_keypress(struct perf_session *session, int c) | |||
695 | } | 693 | } |
696 | } | 694 | } |
697 | 695 | ||
696 | static void *display_thread_tui(void *arg __used) | ||
697 | { | ||
698 | perf_top__tui_browser(&top); | ||
699 | exit_browser(0); | ||
700 | exit(0); | ||
701 | return NULL; | ||
702 | } | ||
703 | |||
698 | static void *display_thread(void *arg __used) | 704 | static void *display_thread(void *arg __used) |
699 | { | 705 | { |
700 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; | 706 | struct pollfd stdin_poll = { .fd = 0, .events = POLLIN }; |
@@ -1005,7 +1011,8 @@ static int __cmd_top(void) | |||
1005 | 1011 | ||
1006 | perf_session__mmap_read(session); | 1012 | perf_session__mmap_read(session); |
1007 | 1013 | ||
1008 | if (pthread_create(&thread, NULL, display_thread, session)) { | 1014 | if (pthread_create(&thread, NULL, (use_browser > 0 ? display_thread_tui : |
1015 | display_thread), session)) { | ||
1009 | printf("Could not create display thread.\n"); | 1016 | printf("Could not create display thread.\n"); |
1010 | exit(-1); | 1017 | exit(-1); |
1011 | } | 1018 | } |
@@ -1078,6 +1085,8 @@ static const struct option options[] = { | |||
1078 | "display this many functions"), | 1085 | "display this many functions"), |
1079 | OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, | 1086 | OPT_BOOLEAN('U', "hide_user_symbols", &top.hide_user_symbols, |
1080 | "hide user symbols"), | 1087 | "hide user symbols"), |
1088 | OPT_BOOLEAN(0, "tui", &use_tui, "Use the TUI interface"), | ||
1089 | OPT_BOOLEAN(0, "stdio", &use_stdio, "Use the stdio interface"), | ||
1081 | OPT_INCR('v', "verbose", &verbose, | 1090 | OPT_INCR('v', "verbose", &verbose, |
1082 | "be more verbose (show counter open errors, etc)"), | 1091 | "be more verbose (show counter open errors, etc)"), |
1083 | OPT_END() | 1092 | OPT_END() |
@@ -1098,6 +1107,20 @@ int cmd_top(int argc, const char **argv, const char *prefix __used) | |||
1098 | if (argc) | 1107 | if (argc) |
1099 | usage_with_options(top_usage, options); | 1108 | usage_with_options(top_usage, options); |
1100 | 1109 | ||
1110 | /* | ||
1111 | * XXX For now start disabled, only using TUI if explicitely asked for. | ||
1112 | * Change that when handle_keys equivalent gets written, live annotation | ||
1113 | * done, etc. | ||
1114 | */ | ||
1115 | use_browser = 0; | ||
1116 | |||
1117 | if (use_stdio) | ||
1118 | use_browser = 0; | ||
1119 | else if (use_tui) | ||
1120 | use_browser = 1; | ||
1121 | |||
1122 | setup_browser(false); | ||
1123 | |||
1101 | /* CPU and PID are mutually exclusive */ | 1124 | /* CPU and PID are mutually exclusive */ |
1102 | if (top.target_tid > 0 && top.cpu_list) { | 1125 | if (top.target_tid > 0 && top.cpu_list) { |
1103 | printf("WARNING: PID switch overriding CPU\n"); | 1126 | printf("WARNING: PID switch overriding CPU\n"); |
diff --git a/tools/perf/util/top.c b/tools/perf/util/top.c index c06cc5386e7e..1d2e2652cd68 100644 --- a/tools/perf/util/top.c +++ b/tools/perf/util/top.c | |||
@@ -158,6 +158,7 @@ float perf_top__decay_samples(struct perf_top *top, struct rb_root *root) | |||
158 | syme = list_entry(top->active_symbols.next, struct sym_entry, node); | 158 | syme = list_entry(top->active_symbols.next, struct sym_entry, node); |
159 | pthread_mutex_unlock(&top->active_symbols_lock); | 159 | pthread_mutex_unlock(&top->active_symbols_lock); |
160 | 160 | ||
161 | top->rb_entries = 0; | ||
161 | list_for_each_entry_safe_from(syme, n, &top->active_symbols, node) { | 162 | list_for_each_entry_safe_from(syme, n, &top->active_symbols, node) { |
162 | syme->snap_count = syme->count[snap]; | 163 | syme->snap_count = syme->count[snap]; |
163 | if (syme->snap_count != 0) { | 164 | if (syme->snap_count != 0) { |
@@ -170,7 +171,11 @@ float perf_top__decay_samples(struct perf_top *top, struct rb_root *root) | |||
170 | continue; | 171 | continue; |
171 | } | 172 | } |
172 | syme->weight = sym_weight(syme, top); | 173 | syme->weight = sym_weight(syme, top); |
173 | rb_insert_active_sym(root, syme); | 174 | |
175 | if ((int)syme->snap_count >= top->count_filter) { | ||
176 | rb_insert_active_sym(root, syme); | ||
177 | ++top->rb_entries; | ||
178 | } | ||
174 | sum_ksamples += syme->snap_count; | 179 | sum_ksamples += syme->snap_count; |
175 | 180 | ||
176 | for (j = 0; j < top->evlist->nr_entries; j++) | 181 | for (j = 0; j < top->evlist->nr_entries; j++) |
diff --git a/tools/perf/util/top.h b/tools/perf/util/top.h index 0467b26dd8d8..611370fa7df8 100644 --- a/tools/perf/util/top.h +++ b/tools/perf/util/top.h | |||
@@ -38,6 +38,11 @@ struct sym_entry { | |||
38 | unsigned long count[0]; | 38 | unsigned long count[0]; |
39 | }; | 39 | }; |
40 | 40 | ||
41 | static inline struct symbol *sym_entry__symbol(struct sym_entry *self) | ||
42 | { | ||
43 | return ((void *)self) + symbol_conf.priv_size; | ||
44 | } | ||
45 | |||
41 | struct perf_top { | 46 | struct perf_top { |
42 | struct perf_evlist *evlist; | 47 | struct perf_evlist *evlist; |
43 | /* | 48 | /* |
@@ -51,7 +56,7 @@ struct perf_top { | |||
51 | u64 exact_samples; | 56 | u64 exact_samples; |
52 | u64 guest_us_samples, guest_kernel_samples; | 57 | u64 guest_us_samples, guest_kernel_samples; |
53 | int print_entries, count_filter, delay_secs; | 58 | int print_entries, count_filter, delay_secs; |
54 | int display_weighted, freq; | 59 | int display_weighted, freq, rb_entries; |
55 | int sym_counter, target_pid, target_tid; | 60 | int sym_counter, target_pid, target_tid; |
56 | bool hide_kernel_symbols, hide_user_symbols, zero; | 61 | bool hide_kernel_symbols, hide_user_symbols, zero; |
57 | const char *cpu_list; | 62 | const char *cpu_list; |
@@ -64,4 +69,12 @@ float perf_top__decay_samples(struct perf_top *top, struct rb_root *root); | |||
64 | void perf_top__find_widths(struct perf_top *top, struct rb_root *root, | 69 | void perf_top__find_widths(struct perf_top *top, struct rb_root *root, |
65 | int *dso_width, int *dso_short_width, int *sym_width); | 70 | int *dso_width, int *dso_short_width, int *sym_width); |
66 | 71 | ||
72 | #ifdef NO_NEWT_SUPPORT | ||
73 | static inline int perf_top__tui_browser(struct perf_top *top __used) | ||
74 | { | ||
75 | return 0; | ||
76 | } | ||
77 | #else | ||
78 | int perf_top__tui_browser(struct perf_top *top); | ||
79 | #endif | ||
67 | #endif /* __PERF_TOP_H */ | 80 | #endif /* __PERF_TOP_H */ |
diff --git a/tools/perf/util/ui/browsers/top.c b/tools/perf/util/ui/browsers/top.c new file mode 100644 index 000000000000..ca6062483a8f --- /dev/null +++ b/tools/perf/util/ui/browsers/top.c | |||
@@ -0,0 +1,136 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2011, Red Hat Inc, Arnaldo Carvalho de Melo <acme@redhat.com> | ||
3 | * | ||
4 | * Parts came from builtin-{top,stat,record}.c, see those files for further | ||
5 | * copyright notes. | ||
6 | * | ||
7 | * Released under the GPL v2. (and only v2, not any later version) | ||
8 | */ | ||
9 | #include "../browser.h" | ||
10 | #include "../helpline.h" | ||
11 | #include "../libslang.h" | ||
12 | #include "../../evlist.h" | ||
13 | #include "../../hist.h" | ||
14 | #include "../../sort.h" | ||
15 | #include "../../symbol.h" | ||
16 | #include "../../top.h" | ||
17 | |||
18 | struct perf_top_browser { | ||
19 | struct ui_browser b; | ||
20 | struct rb_root root; | ||
21 | float sum_ksamples; | ||
22 | int dso_width; | ||
23 | int dso_short_width; | ||
24 | int sym_width; | ||
25 | }; | ||
26 | |||
27 | static void perf_top_browser__write(struct ui_browser *browser, void *entry, int row) | ||
28 | { | ||
29 | struct perf_top_browser *top_browser = container_of(browser, struct perf_top_browser, b); | ||
30 | struct sym_entry *syme = rb_entry(entry, struct sym_entry, rb_node); | ||
31 | bool current_entry = ui_browser__is_current_entry(browser, row); | ||
32 | struct symbol *symbol = sym_entry__symbol(syme); | ||
33 | struct perf_top *top = browser->priv; | ||
34 | int width = browser->width; | ||
35 | double pcnt; | ||
36 | |||
37 | pcnt = 100.0 - (100.0 * ((top_browser->sum_ksamples - syme->snap_count) / | ||
38 | top_browser->sum_ksamples)); | ||
39 | ui_browser__set_percent_color(browser, pcnt, current_entry); | ||
40 | |||
41 | if (top->evlist->nr_entries == 1 || !top->display_weighted) { | ||
42 | slsmg_printf("%20.2f ", syme->weight); | ||
43 | width -= 24; | ||
44 | } else { | ||
45 | slsmg_printf("%9.1f %10ld ", syme->weight, syme->snap_count); | ||
46 | width -= 23; | ||
47 | } | ||
48 | |||
49 | slsmg_printf("%4.1f%%", pcnt); | ||
50 | width -= 7; | ||
51 | |||
52 | if (verbose) { | ||
53 | slsmg_printf(" %016" PRIx64, symbol->start); | ||
54 | width -= 17; | ||
55 | } | ||
56 | |||
57 | slsmg_printf(" %-*.*s ", top_browser->sym_width, top_browser->sym_width, | ||
58 | symbol->name); | ||
59 | width -= top_browser->sym_width; | ||
60 | slsmg_write_nstring(width >= syme->map->dso->long_name_len ? | ||
61 | syme->map->dso->long_name : | ||
62 | syme->map->dso->short_name, width); | ||
63 | } | ||
64 | |||
65 | static void perf_top_browser__update_rb_tree(struct perf_top_browser *browser) | ||
66 | { | ||
67 | struct perf_top *top = browser->b.priv; | ||
68 | |||
69 | browser->root = RB_ROOT; | ||
70 | browser->b.top = NULL; | ||
71 | browser->sum_ksamples = perf_top__decay_samples(top, &browser->root); | ||
72 | perf_top__find_widths(top, &browser->root, &browser->dso_width, | ||
73 | &browser->dso_short_width, | ||
74 | &browser->sym_width); | ||
75 | if (browser->sym_width + browser->dso_width > browser->b.width - 29) { | ||
76 | browser->dso_width = browser->dso_short_width; | ||
77 | if (browser->sym_width + browser->dso_width > browser->b.width - 29) | ||
78 | browser->sym_width = browser->b.width - browser->dso_width - 29; | ||
79 | } | ||
80 | browser->b.nr_entries = top->rb_entries; | ||
81 | } | ||
82 | |||
83 | static int perf_top_browser__run(struct perf_top_browser *browser) | ||
84 | { | ||
85 | int key; | ||
86 | char title[160]; | ||
87 | struct perf_top *top = browser->b.priv; | ||
88 | int delay_msecs = top->delay_secs * 1000; | ||
89 | |||
90 | perf_top_browser__update_rb_tree(browser); | ||
91 | perf_top__header_snprintf(top, title, sizeof(title)); | ||
92 | perf_top__reset_sample_counters(top); | ||
93 | |||
94 | if (ui_browser__show(&browser->b, title, "ESC: exit") < 0) | ||
95 | return -1; | ||
96 | |||
97 | newtFormSetTimer(browser->b.form, delay_msecs); | ||
98 | |||
99 | while (1) { | ||
100 | key = ui_browser__run(&browser->b); | ||
101 | |||
102 | switch (key) { | ||
103 | case -1: | ||
104 | /* FIXME we need to check if it was es.reason == NEWT_EXIT_TIMER */ | ||
105 | perf_top_browser__update_rb_tree(browser); | ||
106 | perf_top__header_snprintf(top, title, sizeof(title)); | ||
107 | perf_top__reset_sample_counters(top); | ||
108 | ui_browser__set_color(&browser->b, NEWT_COLORSET_ROOT); | ||
109 | SLsmg_gotorc(0, 0); | ||
110 | slsmg_write_nstring(title, browser->b.width); | ||
111 | break; | ||
112 | case NEWT_KEY_TAB: | ||
113 | default: | ||
114 | goto out; | ||
115 | } | ||
116 | } | ||
117 | out: | ||
118 | ui_browser__hide(&browser->b); | ||
119 | return key; | ||
120 | } | ||
121 | |||
122 | int perf_top__tui_browser(struct perf_top *top) | ||
123 | { | ||
124 | struct perf_top_browser browser = { | ||
125 | .b = { | ||
126 | .entries = &browser.root, | ||
127 | .refresh = ui_browser__rb_tree_refresh, | ||
128 | .seek = ui_browser__rb_tree_seek, | ||
129 | .write = perf_top_browser__write, | ||
130 | .priv = top, | ||
131 | }, | ||
132 | }; | ||
133 | |||
134 | ui_helpline__push("Press <- or ESC to exit"); | ||
135 | return perf_top_browser__run(&browser); | ||
136 | } | ||