diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/Makefile | 8 | ||||
-rw-r--r-- | tools/perf/builtin-report.c | 47 | ||||
-rw-r--r-- | tools/perf/perf.c | 2 | ||||
-rw-r--r-- | tools/perf/util/cache.h | 14 | ||||
-rw-r--r-- | tools/perf/util/color.c | 5 | ||||
-rw-r--r-- | tools/perf/util/debug.c | 6 | ||||
-rw-r--r-- | tools/perf/util/debug.h | 1 | ||||
-rw-r--r-- | tools/perf/util/hist.h | 5 | ||||
-rw-r--r-- | tools/perf/util/newt.c | 194 | ||||
-rw-r--r-- | tools/perf/util/session.h | 9 |
10 files changed, 270 insertions, 21 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 8a8f52db7e38..0abd25ee595f 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -513,6 +513,14 @@ else | |||
513 | LIB_OBJS += util/probe-finder.o | 513 | LIB_OBJS += util/probe-finder.o |
514 | endif | 514 | endif |
515 | 515 | ||
516 | ifneq ($(shell sh -c "(echo '\#include <newt.h>'; echo 'int main(void) { newtInit(); newtCls(); return newtFinished(); }') | $(CC) -x c - $(ALL_CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 -lnewt -o $(BITBUCKET) $(ALL_LDFLAGS) $(EXTLIBS) "$(QUIET_STDERR)" && echo y"), y) | ||
517 | msg := $(warning newt not found, disables TUI support. Please install newt-devel or libnewt-dev); | ||
518 | BASIC_CFLAGS += -DNO_NEWT_SUPPORT | ||
519 | else | ||
520 | EXTLIBS += -lnewt | ||
521 | LIB_OBJS += util/newt.o | ||
522 | endif | ||
523 | |||
516 | ifndef NO_LIBPERL | 524 | ifndef NO_LIBPERL |
517 | PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` | 525 | PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` |
518 | PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` | 526 | PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` |
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c index f815de25d0fc..1f9f8695f055 100644 --- a/tools/perf/builtin-report.c +++ b/tools/perf/builtin-report.c | |||
@@ -267,6 +267,7 @@ static int __cmd_report(void) | |||
267 | int ret = -EINVAL; | 267 | int ret = -EINVAL; |
268 | struct perf_session *session; | 268 | struct perf_session *session; |
269 | struct rb_node *next; | 269 | struct rb_node *next; |
270 | const char *help = "For a higher level overview, try: perf report --sort comm,dso"; | ||
270 | 271 | ||
271 | session = perf_session__new(input_name, O_RDONLY, force); | 272 | session = perf_session__new(input_name, O_RDONLY, force); |
272 | if (session == NULL) | 273 | if (session == NULL) |
@@ -301,30 +302,38 @@ static int __cmd_report(void) | |||
301 | stats = rb_entry(next, struct event_stat_id, rb_node); | 302 | stats = rb_entry(next, struct event_stat_id, rb_node); |
302 | perf_session__collapse_resort(&stats->hists); | 303 | perf_session__collapse_resort(&stats->hists); |
303 | perf_session__output_resort(&stats->hists, stats->stats.total); | 304 | perf_session__output_resort(&stats->hists, stats->stats.total); |
304 | if (rb_first(&session->stats_by_id) == | ||
305 | rb_last(&session->stats_by_id)) | ||
306 | fprintf(stdout, "# Samples: %Ld\n#\n", | ||
307 | stats->stats.total); | ||
308 | else | ||
309 | fprintf(stdout, "# Samples: %Ld %s\n#\n", | ||
310 | stats->stats.total, | ||
311 | __event_name(stats->type, stats->config)); | ||
312 | 305 | ||
313 | perf_session__fprintf_hists(&stats->hists, NULL, false, stdout, | 306 | if (use_browser) |
307 | perf_session__browse_hists(&stats->hists, | ||
308 | stats->stats.total, help); | ||
309 | else { | ||
310 | if (rb_first(&session->stats_by_id) == | ||
311 | rb_last(&session->stats_by_id)) | ||
312 | fprintf(stdout, "# Samples: %Ld\n#\n", | ||
313 | stats->stats.total); | ||
314 | else | ||
315 | fprintf(stdout, "# Samples: %Ld %s\n#\n", | ||
316 | stats->stats.total, | ||
317 | __event_name(stats->type, stats->config)); | ||
318 | |||
319 | perf_session__fprintf_hists(&stats->hists, NULL, false, stdout, | ||
314 | stats->stats.total); | 320 | stats->stats.total); |
315 | fprintf(stdout, "\n\n"); | 321 | fprintf(stdout, "\n\n"); |
322 | } | ||
323 | |||
316 | next = rb_next(&stats->rb_node); | 324 | next = rb_next(&stats->rb_node); |
317 | } | 325 | } |
318 | 326 | ||
319 | if (sort_order == default_sort_order && | 327 | if (!use_browser && sort_order == default_sort_order && |
320 | parent_pattern == default_parent_pattern) | 328 | parent_pattern == default_parent_pattern) { |
321 | fprintf(stdout, "#\n# (For a higher level overview, try: perf report --sort comm,dso)\n#\n"); | 329 | fprintf(stdout, "#\n# (%s)\n#\n", help); |
322 | 330 | ||
323 | if (show_threads) { | 331 | if (show_threads) { |
324 | bool raw_printing_style = !strcmp(pretty_printing_style, "raw"); | 332 | bool style = !strcmp(pretty_printing_style, "raw"); |
325 | perf_read_values_display(stdout, &show_threads_values, | 333 | perf_read_values_display(stdout, &show_threads_values, |
326 | raw_printing_style); | 334 | style); |
327 | perf_read_values_destroy(&show_threads_values); | 335 | perf_read_values_destroy(&show_threads_values); |
336 | } | ||
328 | } | 337 | } |
329 | out_delete: | 338 | out_delete: |
330 | perf_session__delete(session); | 339 | perf_session__delete(session); |
@@ -447,7 +456,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __used) | |||
447 | { | 456 | { |
448 | argc = parse_options(argc, argv, options, report_usage, 0); | 457 | argc = parse_options(argc, argv, options, report_usage, 0); |
449 | 458 | ||
450 | setup_pager(); | 459 | setup_browser(); |
451 | 460 | ||
452 | if (symbol__init() < 0) | 461 | if (symbol__init() < 0) |
453 | return -1; | 462 | return -1; |
diff --git a/tools/perf/perf.c b/tools/perf/perf.c index 57cb107c1f13..9ff186b57cb7 100644 --- a/tools/perf/perf.c +++ b/tools/perf/perf.c | |||
@@ -265,6 +265,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv) | |||
265 | if (status) | 265 | if (status) |
266 | return status & 0xff; | 266 | return status & 0xff; |
267 | 267 | ||
268 | exit_browser(); | ||
269 | |||
268 | /* Somebody closed stdout? */ | 270 | /* Somebody closed stdout? */ |
269 | if (fstat(fileno(stdout), &st)) | 271 | if (fstat(fileno(stdout), &st)) |
270 | return 0; | 272 | return 0; |
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h index 918eb376abe3..47b12a3d11bf 100644 --- a/tools/perf/util/cache.h +++ b/tools/perf/util/cache.h | |||
@@ -1,6 +1,7 @@ | |||
1 | #ifndef __PERF_CACHE_H | 1 | #ifndef __PERF_CACHE_H |
2 | #define __PERF_CACHE_H | 2 | #define __PERF_CACHE_H |
3 | 3 | ||
4 | #include <stdbool.h> | ||
4 | #include "util.h" | 5 | #include "util.h" |
5 | #include "strbuf.h" | 6 | #include "strbuf.h" |
6 | #include "../perf.h" | 7 | #include "../perf.h" |
@@ -69,6 +70,19 @@ extern const char *pager_program; | |||
69 | extern int pager_in_use(void); | 70 | extern int pager_in_use(void); |
70 | extern int pager_use_color; | 71 | extern int pager_use_color; |
71 | 72 | ||
73 | extern bool use_browser; | ||
74 | |||
75 | #ifdef NO_NEWT_SUPPORT | ||
76 | static inline void setup_browser(void) | ||
77 | { | ||
78 | setup_pager(); | ||
79 | } | ||
80 | static inline void exit_browser(void) {} | ||
81 | #else | ||
82 | void setup_browser(void); | ||
83 | void exit_browser(void); | ||
84 | #endif | ||
85 | |||
72 | extern const char *editor_program; | 86 | extern const char *editor_program; |
73 | extern const char *excludes_file; | 87 | extern const char *excludes_file; |
74 | 88 | ||
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c index e88bca55a599..9da01914e0af 100644 --- a/tools/perf/util/color.c +++ b/tools/perf/util/color.c | |||
@@ -203,7 +203,10 @@ int color_fprintf(FILE *fp, const char *color, const char *fmt, ...) | |||
203 | int r; | 203 | int r; |
204 | 204 | ||
205 | va_start(args, fmt); | 205 | va_start(args, fmt); |
206 | r = color_vfprintf(fp, color, fmt, args); | 206 | if (use_browser) |
207 | r = vfprintf(fp, fmt, args); | ||
208 | else | ||
209 | r = color_vfprintf(fp, color, fmt, args); | ||
207 | va_end(args); | 210 | va_end(args); |
208 | return r; | 211 | return r; |
209 | } | 212 | } |
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c index 0905600c3851..033d66db863a 100644 --- a/tools/perf/util/debug.c +++ b/tools/perf/util/debug.c | |||
@@ -6,6 +6,7 @@ | |||
6 | #include <stdarg.h> | 6 | #include <stdarg.h> |
7 | #include <stdio.h> | 7 | #include <stdio.h> |
8 | 8 | ||
9 | #include "cache.h" | ||
9 | #include "color.h" | 10 | #include "color.h" |
10 | #include "event.h" | 11 | #include "event.h" |
11 | #include "debug.h" | 12 | #include "debug.h" |
@@ -21,7 +22,10 @@ int eprintf(int level, const char *fmt, ...) | |||
21 | 22 | ||
22 | if (verbose >= level) { | 23 | if (verbose >= level) { |
23 | va_start(args, fmt); | 24 | va_start(args, fmt); |
24 | ret = vfprintf(stderr, fmt, args); | 25 | if (use_browser) |
26 | ret = browser__show_help(fmt, args); | ||
27 | else | ||
28 | ret = vfprintf(stderr, fmt, args); | ||
25 | va_end(args); | 29 | va_end(args); |
26 | } | 30 | } |
27 | 31 | ||
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h index 58720a181591..03accb867996 100644 --- a/tools/perf/util/debug.h +++ b/tools/perf/util/debug.h | |||
@@ -9,5 +9,6 @@ extern int dump_trace; | |||
9 | 9 | ||
10 | int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); | 10 | int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); |
11 | void trace_event(event_t *event); | 11 | void trace_event(event_t *event); |
12 | int browser__show_help(const char *format, va_list ap); | ||
12 | 13 | ||
13 | #endif /* __PERF_DEBUG_H */ | 14 | #endif /* __PERF_DEBUG_H */ |
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h index 16f360cce5bf..fe366ce5db45 100644 --- a/tools/perf/util/hist.h +++ b/tools/perf/util/hist.h | |||
@@ -18,6 +18,11 @@ struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists, | |||
18 | u64 count, bool *hit); | 18 | u64 count, bool *hit); |
19 | extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); | 19 | extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); |
20 | extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); | 20 | extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); |
21 | size_t hist_entry__fprintf(struct hist_entry *self, | ||
22 | struct perf_session *pair_session, | ||
23 | bool show_displacement, | ||
24 | long displacement, FILE *fp, | ||
25 | u64 session_total); | ||
21 | void hist_entry__free(struct hist_entry *); | 26 | void hist_entry__free(struct hist_entry *); |
22 | 27 | ||
23 | void perf_session__output_resort(struct rb_root *hists, u64 total_samples); | 28 | void perf_session__output_resort(struct rb_root *hists, u64 total_samples); |
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c new file mode 100644 index 000000000000..3d3a936acb67 --- /dev/null +++ b/tools/perf/util/newt.c | |||
@@ -0,0 +1,194 @@ | |||
1 | #define _GNU_SOURCE | ||
2 | #include <stdio.h> | ||
3 | #undef _GNU_SOURCE | ||
4 | |||
5 | #include <stdlib.h> | ||
6 | #include <newt.h> | ||
7 | |||
8 | #include "cache.h" | ||
9 | #include "hist.h" | ||
10 | #include "session.h" | ||
11 | #include "sort.h" | ||
12 | #include "symbol.h" | ||
13 | |||
14 | static size_t hist_entry__append_browser(struct hist_entry *self, | ||
15 | newtComponent listbox, u64 total) | ||
16 | { | ||
17 | char bf[1024]; | ||
18 | size_t len; | ||
19 | FILE *fp; | ||
20 | |||
21 | if (symbol_conf.exclude_other && !self->parent) | ||
22 | return 0; | ||
23 | |||
24 | fp = fmemopen(bf, sizeof(bf), "w"); | ||
25 | if (fp == NULL) | ||
26 | return 0; | ||
27 | |||
28 | len = hist_entry__fprintf(self, NULL, false, 0, fp, total); | ||
29 | |||
30 | fclose(fp); | ||
31 | newtListboxAppendEntry(listbox, bf, self); | ||
32 | return len; | ||
33 | } | ||
34 | |||
35 | static void hist_entry__annotate_browser(struct hist_entry *self) | ||
36 | { | ||
37 | FILE *fp; | ||
38 | struct winsize ws; | ||
39 | newtComponent form, listbox; | ||
40 | struct newtExitStruct es; | ||
41 | char *str; | ||
42 | size_t line_len, max_line_len = 0; | ||
43 | size_t max_usable_width; | ||
44 | char *line = NULL; | ||
45 | |||
46 | if (self->sym == NULL) | ||
47 | return; | ||
48 | |||
49 | if (asprintf(&str, "perf annotate %s | expand", self->sym->name) < 0) | ||
50 | return; | ||
51 | |||
52 | fp = popen(str, "r"); | ||
53 | if (fp == NULL) | ||
54 | goto out_free_str; | ||
55 | |||
56 | newtPushHelpLine("Press ESC to exit"); | ||
57 | get_term_dimensions(&ws); | ||
58 | listbox = newtListbox(0, 0, ws.ws_row - 5, NEWT_FLAG_SCROLL); | ||
59 | |||
60 | while (!feof(fp)) { | ||
61 | if (getline(&line, &line_len, fp) < 0 || !line_len) | ||
62 | break; | ||
63 | while (line_len != 0 && isspace(line[line_len - 1])) | ||
64 | line[--line_len] = '\0'; | ||
65 | |||
66 | if (line_len > max_line_len) | ||
67 | max_line_len = line_len; | ||
68 | newtListboxAppendEntry(listbox, line, NULL); | ||
69 | } | ||
70 | fclose(fp); | ||
71 | free(line); | ||
72 | |||
73 | max_usable_width = ws.ws_col - 22; | ||
74 | if (max_line_len > max_usable_width) | ||
75 | max_line_len = max_usable_width; | ||
76 | |||
77 | newtListboxSetWidth(listbox, max_line_len); | ||
78 | |||
79 | newtCenteredWindow(max_line_len + 2, ws.ws_row - 5, self->sym->name); | ||
80 | form = newtForm(NULL, NULL, 0); | ||
81 | newtFormAddHotKey(form, NEWT_KEY_ESCAPE); | ||
82 | newtFormAddComponents(form, listbox, NULL); | ||
83 | |||
84 | newtFormRun(form, &es); | ||
85 | newtFormDestroy(form); | ||
86 | newtPopWindow(); | ||
87 | newtPopHelpLine(); | ||
88 | out_free_str: | ||
89 | free(str); | ||
90 | } | ||
91 | |||
92 | void perf_session__browse_hists(struct rb_root *hists, u64 session_total, | ||
93 | const char *helpline) | ||
94 | { | ||
95 | struct sort_entry *se; | ||
96 | struct rb_node *nd; | ||
97 | unsigned int width; | ||
98 | char *col_width = symbol_conf.col_width_list_str; | ||
99 | struct winsize ws; | ||
100 | size_t max_len = 0; | ||
101 | char str[1024]; | ||
102 | newtComponent form, listbox; | ||
103 | struct newtExitStruct es; | ||
104 | |||
105 | snprintf(str, sizeof(str), "Samples: %Ld", session_total); | ||
106 | newtDrawRootText(0, 0, str); | ||
107 | newtPushHelpLine(helpline); | ||
108 | |||
109 | get_term_dimensions(&ws); | ||
110 | |||
111 | form = newtForm(NULL, NULL, 0); | ||
112 | newtFormAddHotKey(form, NEWT_KEY_ESCAPE); | ||
113 | |||
114 | listbox = newtListbox(1, 1, ws.ws_row - 2, (NEWT_FLAG_SCROLL | | ||
115 | NEWT_FLAG_BORDER | | ||
116 | NEWT_FLAG_RETURNEXIT)); | ||
117 | |||
118 | list_for_each_entry(se, &hist_entry__sort_list, list) { | ||
119 | if (se->elide) | ||
120 | continue; | ||
121 | width = strlen(se->header); | ||
122 | if (se->width) { | ||
123 | if (symbol_conf.col_width_list_str) { | ||
124 | if (col_width) { | ||
125 | *se->width = atoi(col_width); | ||
126 | col_width = strchr(col_width, ','); | ||
127 | if (col_width) | ||
128 | ++col_width; | ||
129 | } | ||
130 | } | ||
131 | *se->width = max(*se->width, width); | ||
132 | } | ||
133 | } | ||
134 | |||
135 | for (nd = rb_first(hists); nd; nd = rb_next(nd)) { | ||
136 | struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); | ||
137 | size_t len = hist_entry__append_browser(h, listbox, session_total); | ||
138 | if (len > max_len) | ||
139 | max_len = len; | ||
140 | } | ||
141 | |||
142 | newtListboxSetWidth(listbox, max_len); | ||
143 | newtFormAddComponents(form, listbox, NULL); | ||
144 | |||
145 | while (1) { | ||
146 | struct hist_entry *selection; | ||
147 | |||
148 | newtFormRun(form, &es); | ||
149 | if (es.reason == NEWT_EXIT_HOTKEY) | ||
150 | break; | ||
151 | selection = newtListboxGetCurrent(listbox); | ||
152 | hist_entry__annotate_browser(selection); | ||
153 | } | ||
154 | |||
155 | newtFormDestroy(form); | ||
156 | } | ||
157 | |||
158 | int browser__show_help(const char *format, va_list ap) | ||
159 | { | ||
160 | int ret; | ||
161 | static int backlog; | ||
162 | static char msg[1024]; | ||
163 | |||
164 | ret = vsnprintf(msg + backlog, sizeof(msg) - backlog, format, ap); | ||
165 | backlog += ret; | ||
166 | |||
167 | if (msg[backlog - 1] == '\n') { | ||
168 | newtPopHelpLine(); | ||
169 | newtPushHelpLine(msg); | ||
170 | newtRefresh(); | ||
171 | backlog = 0; | ||
172 | } | ||
173 | |||
174 | return ret; | ||
175 | } | ||
176 | |||
177 | bool use_browser; | ||
178 | |||
179 | void setup_browser(void) | ||
180 | { | ||
181 | if (!isatty(1)) | ||
182 | return; | ||
183 | |||
184 | use_browser = true; | ||
185 | newtInit(); | ||
186 | newtCls(); | ||
187 | newtPushHelpLine(" "); | ||
188 | } | ||
189 | |||
190 | void exit_browser(void) | ||
191 | { | ||
192 | if (use_browser) | ||
193 | newtFinished(); | ||
194 | } | ||
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 5c33417eebb3..34d73395baac 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -86,4 +86,13 @@ static inline struct map * | |||
86 | { | 86 | { |
87 | return map_groups__new_module(&self->kmaps, start, filename); | 87 | return map_groups__new_module(&self->kmaps, start, filename); |
88 | } | 88 | } |
89 | |||
90 | #ifdef NO_NEWT_SUPPORT | ||
91 | static inline void perf_session__browse_hists(struct rb_root *hists __used, | ||
92 | u64 session_total __used, | ||
93 | const char *helpline __used) {} | ||
94 | #else | ||
95 | void perf_session__browse_hists(struct rb_root *hists, u64 session_total, | ||
96 | const char *helpline); | ||
97 | #endif | ||
89 | #endif /* __PERF_SESSION_H */ | 98 | #endif /* __PERF_SESSION_H */ |