aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--tools/perf/Makefile8
-rw-r--r--tools/perf/builtin-report.c47
-rw-r--r--tools/perf/perf.c2
-rw-r--r--tools/perf/util/cache.h14
-rw-r--r--tools/perf/util/color.c5
-rw-r--r--tools/perf/util/debug.c6
-rw-r--r--tools/perf/util/debug.h1
-rw-r--r--tools/perf/util/hist.h5
-rw-r--r--tools/perf/util/newt.c194
-rw-r--r--tools/perf/util/session.h9
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
514endif 514endif
515 515
516ifneq ($(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
519else
520 EXTLIBS += -lnewt
521 LIB_OBJS += util/newt.o
522endif
523
516ifndef NO_LIBPERL 524ifndef NO_LIBPERL
517PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null` 525PERL_EMBED_LDOPTS = `perl -MExtUtils::Embed -e ldopts 2>/dev/null`
518PERL_EMBED_CCOPTS = `perl -MExtUtils::Embed -e ccopts 2>/dev/null` 526PERL_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 }
329out_delete: 338out_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;
69extern int pager_in_use(void); 70extern int pager_in_use(void);
70extern int pager_use_color; 71extern int pager_use_color;
71 72
73extern bool use_browser;
74
75#ifdef NO_NEWT_SUPPORT
76static inline void setup_browser(void)
77{
78 setup_pager();
79}
80static inline void exit_browser(void) {}
81#else
82void setup_browser(void);
83void exit_browser(void);
84#endif
85
72extern const char *editor_program; 86extern const char *editor_program;
73extern const char *excludes_file; 87extern 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
10int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 10int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
11void trace_event(event_t *event); 11void trace_event(event_t *event);
12int 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);
19extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *); 19extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
20extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *); 20extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
21size_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);
21void hist_entry__free(struct hist_entry *); 26void hist_entry__free(struct hist_entry *);
22 27
23void perf_session__output_resort(struct rb_root *hists, u64 total_samples); 28void 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
14static 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
35static 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();
88out_free_str:
89 free(str);
90}
91
92void 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
158int 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
177bool use_browser;
178
179void setup_browser(void)
180{
181 if (!isatty(1))
182 return;
183
184 use_browser = true;
185 newtInit();
186 newtCls();
187 newtPushHelpLine(" ");
188}
189
190void 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
91static inline void perf_session__browse_hists(struct rb_root *hists __used,
92 u64 session_total __used,
93 const char *helpline __used) {}
94#else
95void 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 */