aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Makefile8
-rw-r--r--tools/perf/builtin-annotate.c10
-rw-r--r--tools/perf/builtin-record.c16
-rw-r--r--tools/perf/builtin-report.c47
-rw-r--r--tools/perf/builtin-top.c47
-rw-r--r--tools/perf/perf.c4
-rw-r--r--tools/perf/perf.h4
-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.h11
-rw-r--r--tools/perf/util/hist.c50
-rw-r--r--tools/perf/util/hist.h5
-rw-r--r--tools/perf/util/include/linux/kernel.h9
-rw-r--r--tools/perf/util/newt.c207
-rw-r--r--tools/perf/util/parse-events.c4
-rw-r--r--tools/perf/util/session.h9
-rw-r--r--tools/perf/util/symbol.c29
-rw-r--r--tools/perf/util/symbol.h16
19 files changed, 419 insertions, 82 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-annotate.c b/tools/perf/builtin-annotate.c
index 6ad7148451c5..45d14660d53d 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -452,6 +452,16 @@ static void annotate_sym(struct hist_entry *he)
452 if (!filename) 452 if (!filename)
453 return; 453 return;
454 454
455 if (dso->origin == DSO__ORIG_KERNEL) {
456 if (dso->annotate_warned)
457 return;
458 dso->annotate_warned = 1;
459 pr_err("Can't annotate %s: No vmlinux file was found in the "
460 "path:\n", sym->name);
461 vmlinux_path__fprintf(stderr);
462 return;
463 }
464
455 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__, 465 pr_debug("%s: filename=%s, sym=%s, start=%#Lx, end=%#Lx\n", __func__,
456 filename, sym->name, map->unmap_ip(map, sym->start), 466 filename, sym->name, map->unmap_ip(map, sym->start),
457 map->unmap_ip(map, sym->end)); 467 map->unmap_ip(map, sym->end));
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 3b8b6387c47c..962cdbf44ae9 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -225,7 +225,7 @@ static struct perf_header_attr *get_header_attr(struct perf_event_attr *a, int n
225 return h_attr; 225 return h_attr;
226} 226}
227 227
228static void create_counter(int counter, int cpu, pid_t pid) 228static void create_counter(int counter, int cpu, pid_t pid, bool forks)
229{ 229{
230 char *filter = filters[counter]; 230 char *filter = filters[counter];
231 struct perf_event_attr *attr = attrs + counter; 231 struct perf_event_attr *attr = attrs + counter;
@@ -277,6 +277,9 @@ static void create_counter(int counter, int cpu, pid_t pid)
277 attr->inherit = inherit; 277 attr->inherit = inherit;
278 attr->disabled = 1; 278 attr->disabled = 1;
279 279
280 if (forks)
281 attr->enable_on_exec = 1;
282
280try_again: 283try_again:
281 fd[nr_cpu][counter] = sys_perf_event_open(attr, pid, cpu, group_fd, 0); 284 fd[nr_cpu][counter] = sys_perf_event_open(attr, pid, cpu, group_fd, 0);
282 285
@@ -284,7 +287,8 @@ try_again:
284 int err = errno; 287 int err = errno;
285 288
286 if (err == EPERM || err == EACCES) 289 if (err == EPERM || err == EACCES)
287 die("Permission error - are you root?\n"); 290 die("Permission error - are you root?\n"
291 "\t Consider tweaking /proc/sys/kernel/perf_event_paranoid.\n");
288 else if (err == ENODEV && profile_cpu != -1) 292 else if (err == ENODEV && profile_cpu != -1)
289 die("No such device - did you specify an out-of-range profile CPU?\n"); 293 die("No such device - did you specify an out-of-range profile CPU?\n");
290 294
@@ -380,13 +384,13 @@ try_again:
380 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE); 384 ioctl(fd[nr_cpu][counter], PERF_EVENT_IOC_ENABLE);
381} 385}
382 386
383static void open_counters(int cpu, pid_t pid) 387static void open_counters(int cpu, pid_t pid, bool forks)
384{ 388{
385 int counter; 389 int counter;
386 390
387 group_fd = -1; 391 group_fd = -1;
388 for (counter = 0; counter < nr_counters; counter++) 392 for (counter = 0; counter < nr_counters; counter++)
389 create_counter(counter, cpu, pid); 393 create_counter(counter, cpu, pid, forks);
390 394
391 nr_cpu++; 395 nr_cpu++;
392} 396}
@@ -546,11 +550,11 @@ static int __cmd_record(int argc, const char **argv)
546 550
547 551
548 if ((!system_wide && !inherit) || profile_cpu != -1) { 552 if ((!system_wide && !inherit) || profile_cpu != -1) {
549 open_counters(profile_cpu, target_pid); 553 open_counters(profile_cpu, target_pid, forks);
550 } else { 554 } else {
551 nr_cpus = read_cpu_map(); 555 nr_cpus = read_cpu_map();
552 for (i = 0; i < nr_cpus; i++) 556 for (i = 0; i < nr_cpus; i++)
553 open_counters(cpumap[i], target_pid); 557 open_counters(cpumap[i], target_pid, forks);
554 } 558 }
555 559
556 if (file_new) { 560 if (file_new) {
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/builtin-top.c b/tools/perf/builtin-top.c
index 1f529321607e..887ebbf5d1ff 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -133,7 +133,7 @@ static inline struct symbol *sym_entry__symbol(struct sym_entry *self)
133 return ((void *)self) + symbol_conf.priv_size; 133 return ((void *)self) + symbol_conf.priv_size;
134} 134}
135 135
136static void get_term_dimensions(struct winsize *ws) 136void get_term_dimensions(struct winsize *ws)
137{ 137{
138 char *s = getenv("LINES"); 138 char *s = getenv("LINES");
139 139
@@ -169,7 +169,7 @@ static void sig_winch_handler(int sig __used)
169 update_print_entries(&winsize); 169 update_print_entries(&winsize);
170} 170}
171 171
172static void parse_source(struct sym_entry *syme) 172static int parse_source(struct sym_entry *syme)
173{ 173{
174 struct symbol *sym; 174 struct symbol *sym;
175 struct sym_entry_source *source; 175 struct sym_entry_source *source;
@@ -180,12 +180,21 @@ static void parse_source(struct sym_entry *syme)
180 u64 len; 180 u64 len;
181 181
182 if (!syme) 182 if (!syme)
183 return; 183 return -1;
184
185 sym = sym_entry__symbol(syme);
186 map = syme->map;
187
188 /*
189 * We can't annotate with just /proc/kallsyms
190 */
191 if (map->dso->origin == DSO__ORIG_KERNEL)
192 return -1;
184 193
185 if (syme->src == NULL) { 194 if (syme->src == NULL) {
186 syme->src = zalloc(sizeof(*source)); 195 syme->src = zalloc(sizeof(*source));
187 if (syme->src == NULL) 196 if (syme->src == NULL)
188 return; 197 return -1;
189 pthread_mutex_init(&syme->src->lock, NULL); 198 pthread_mutex_init(&syme->src->lock, NULL);
190 } 199 }
191 200
@@ -195,9 +204,6 @@ static void parse_source(struct sym_entry *syme)
195 pthread_mutex_lock(&source->lock); 204 pthread_mutex_lock(&source->lock);
196 goto out_assign; 205 goto out_assign;
197 } 206 }
198
199 sym = sym_entry__symbol(syme);
200 map = syme->map;
201 path = map->dso->long_name; 207 path = map->dso->long_name;
202 208
203 len = sym->end - sym->start; 209 len = sym->end - sym->start;
@@ -209,7 +215,7 @@ static void parse_source(struct sym_entry *syme)
209 215
210 file = popen(command, "r"); 216 file = popen(command, "r");
211 if (!file) 217 if (!file)
212 return; 218 return -1;
213 219
214 pthread_mutex_lock(&source->lock); 220 pthread_mutex_lock(&source->lock);
215 source->lines_tail = &source->lines; 221 source->lines_tail = &source->lines;
@@ -245,6 +251,7 @@ static void parse_source(struct sym_entry *syme)
245out_assign: 251out_assign:
246 sym_filter_entry = syme; 252 sym_filter_entry = syme;
247 pthread_mutex_unlock(&source->lock); 253 pthread_mutex_unlock(&source->lock);
254 return 0;
248} 255}
249 256
250static void __zero_source_counters(struct sym_entry *syme) 257static void __zero_source_counters(struct sym_entry *syme)
@@ -411,6 +418,7 @@ static double sym_weight(const struct sym_entry *sym)
411 418
412static long samples; 419static long samples;
413static long userspace_samples; 420static long userspace_samples;
421static long exact_samples;
414static const char CONSOLE_CLEAR[] = ""; 422static const char CONSOLE_CLEAR[] = "";
415 423
416static void __list_insert_active_sym(struct sym_entry *syme) 424static void __list_insert_active_sym(struct sym_entry *syme)
@@ -451,6 +459,7 @@ static void print_sym_table(void)
451 int counter, snap = !display_weighted ? sym_counter : 0; 459 int counter, snap = !display_weighted ? sym_counter : 0;
452 float samples_per_sec = samples/delay_secs; 460 float samples_per_sec = samples/delay_secs;
453 float ksamples_per_sec = (samples-userspace_samples)/delay_secs; 461 float ksamples_per_sec = (samples-userspace_samples)/delay_secs;
462 float esamples_percent = (100.0*exact_samples)/samples;
454 float sum_ksamples = 0.0; 463 float sum_ksamples = 0.0;
455 struct sym_entry *syme, *n; 464 struct sym_entry *syme, *n;
456 struct rb_root tmp = RB_ROOT; 465 struct rb_root tmp = RB_ROOT;
@@ -458,7 +467,7 @@ static void print_sym_table(void)
458 int sym_width = 0, dso_width = 0, dso_short_width = 0; 467 int sym_width = 0, dso_width = 0, dso_short_width = 0;
459 const int win_width = winsize.ws_col - 1; 468 const int win_width = winsize.ws_col - 1;
460 469
461 samples = userspace_samples = 0; 470 samples = userspace_samples = exact_samples = 0;
462 471
463 /* Sort the active symbols */ 472 /* Sort the active symbols */
464 pthread_mutex_lock(&active_symbols_lock); 473 pthread_mutex_lock(&active_symbols_lock);
@@ -489,9 +498,10 @@ static void print_sym_table(void)
489 puts(CONSOLE_CLEAR); 498 puts(CONSOLE_CLEAR);
490 499
491 printf("%-*.*s\n", win_width, win_width, graph_dotted_line); 500 printf("%-*.*s\n", win_width, win_width, graph_dotted_line);
492 printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% [", 501 printf( " PerfTop:%8.0f irqs/sec kernel:%4.1f%% exact: %4.1f%% [",
493 samples_per_sec, 502 samples_per_sec,
494 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec))); 503 100.0 - (100.0*((samples_per_sec-ksamples_per_sec)/samples_per_sec)),
504 esamples_percent);
495 505
496 if (nr_counters == 1 || !display_weighted) { 506 if (nr_counters == 1 || !display_weighted) {
497 printf("%Ld", (u64)attrs[0].sample_period); 507 printf("%Ld", (u64)attrs[0].sample_period);
@@ -960,6 +970,9 @@ static void event__process_sample(const event_t *self,
960 return; 970 return;
961 } 971 }
962 972
973 if (self->header.misc & PERF_RECORD_MISC_EXACT)
974 exact_samples++;
975
963 if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 || 976 if (event__preprocess_sample(self, session, &al, symbol_filter) < 0 ||
964 al.filtered) 977 al.filtered)
965 return; 978 return;
@@ -990,7 +1003,17 @@ static void event__process_sample(const event_t *self,
990 if (sym_filter_entry_sched) { 1003 if (sym_filter_entry_sched) {
991 sym_filter_entry = sym_filter_entry_sched; 1004 sym_filter_entry = sym_filter_entry_sched;
992 sym_filter_entry_sched = NULL; 1005 sym_filter_entry_sched = NULL;
993 parse_source(sym_filter_entry); 1006 if (parse_source(sym_filter_entry) < 0) {
1007 struct symbol *sym = sym_entry__symbol(sym_filter_entry);
1008
1009 pr_err("Can't annotate %s", sym->name);
1010 if (sym_filter_entry->map->dso->origin == DSO__ORIG_KERNEL) {
1011 pr_err(": No vmlinux file was found in the path:\n");
1012 vmlinux_path__fprintf(stderr);
1013 } else
1014 pr_err(".\n");
1015 exit(1);
1016 }
994 } 1017 }
995 1018
996 syme = symbol__priv(al.sym); 1019 syme = symbol__priv(al.sym);
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 57cb107c1f13..0d4b9edfab12 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -16,6 +16,8 @@
16#include "util/string.h" 16#include "util/string.h"
17#include "util/debugfs.h" 17#include "util/debugfs.h"
18 18
19bool use_browser;
20
19const char perf_usage_string[] = 21const char perf_usage_string[] =
20 "perf [--version] [--help] COMMAND [ARGS]"; 22 "perf [--version] [--help] COMMAND [ARGS]";
21 23
@@ -265,6 +267,8 @@ static int run_builtin(struct cmd_struct *p, int argc, const char **argv)
265 if (status) 267 if (status)
266 return status & 0xff; 268 return status & 0xff;
267 269
270 exit_browser();
271
268 /* Somebody closed stdout? */ 272 /* Somebody closed stdout? */
269 if (fstat(fileno(stdout), &st)) 273 if (fstat(fileno(stdout), &st))
270 return 0; 274 return 0;
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 6fb379bc1d1f..aa786158b668 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -1,6 +1,10 @@
1#ifndef _PERF_PERF_H 1#ifndef _PERF_PERF_H
2#define _PERF_PERF_H 2#define _PERF_PERF_H
3 3
4struct winsize;
5
6void get_term_dimensions(struct winsize *ws);
7
4#if defined(__i386__) 8#if defined(__i386__)
5#include "../../arch/x86/include/asm/unistd.h" 9#include "../../arch/x86/include/asm/unistd.h"
6#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory") 10#define rmb() asm volatile("lock; addl $0,0(%%esp)" ::: "memory")
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 c6c24c522dea..0172edf3f153 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -7,9 +7,16 @@
7extern int verbose; 7extern int verbose;
8extern int dump_trace; 8extern int dump_trace;
9 9
10int eprintf(int level,
11 const char *fmt, ...) __attribute__((format(printf, 2, 3)));
12int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2))); 10int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
13void trace_event(event_t *event); 11void trace_event(event_t *event);
14 12
13#ifdef NO_NEWT_SUPPORT
14static inline int browser__show_help(const char *format __used, va_list ap __used)
15{
16 return 0;
17}
18#else
19int browser__show_help(const char *format, va_list ap);
20#endif
21
15#endif /* __PERF_DEBUG_H */ 22#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index bdcfd6190b21..1a4e8376d843 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -455,11 +455,11 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
455 return ret; 455 return ret;
456} 456}
457 457
458static size_t hist_entry__fprintf(struct hist_entry *self, 458size_t hist_entry__fprintf(struct hist_entry *self,
459 struct perf_session *pair_session, 459 struct perf_session *pair_session,
460 bool show_displacement, 460 bool show_displacement,
461 long displacement, FILE *fp, 461 long displacement, FILE *fp,
462 u64 session_total) 462 u64 session_total)
463{ 463{
464 struct sort_entry *se; 464 struct sort_entry *se;
465 u64 count, total; 465 u64 count, total;
@@ -485,9 +485,9 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
485 485
486 if (symbol_conf.show_nr_samples) { 486 if (symbol_conf.show_nr_samples) {
487 if (sep) 487 if (sep)
488 fprintf(fp, "%c%lld", *sep, count); 488 ret += fprintf(fp, "%c%lld", *sep, count);
489 else 489 else
490 fprintf(fp, "%11lld", count); 490 ret += fprintf(fp, "%11lld", count);
491 } 491 }
492 492
493 if (pair_session) { 493 if (pair_session) {
@@ -518,9 +518,9 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
518 snprintf(bf, sizeof(bf), " "); 518 snprintf(bf, sizeof(bf), " ");
519 519
520 if (sep) 520 if (sep)
521 fprintf(fp, "%c%s", *sep, bf); 521 ret += fprintf(fp, "%c%s", *sep, bf);
522 else 522 else
523 fprintf(fp, "%6.6s", bf); 523 ret += fprintf(fp, "%6.6s", bf);
524 } 524 }
525 } 525 }
526 526
@@ -528,27 +528,27 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
528 if (se->elide) 528 if (se->elide)
529 continue; 529 continue;
530 530
531 fprintf(fp, "%s", sep ?: " "); 531 ret += fprintf(fp, "%s", sep ?: " ");
532 ret += se->print(fp, self, se->width ? *se->width : 0); 532 ret += se->print(fp, self, se->width ? *se->width : 0);
533 } 533 }
534 534
535 ret += fprintf(fp, "\n"); 535 return ret + fprintf(fp, "\n");
536 536}
537 if (symbol_conf.use_callchain) {
538 int left_margin = 0;
539 537
540 if (sort__first_dimension == SORT_COMM) { 538static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
541 se = list_first_entry(&hist_entry__sort_list, typeof(*se), 539 u64 session_total)
542 list); 540{
543 left_margin = se->width ? *se->width : 0; 541 int left_margin = 0;
544 left_margin -= thread__comm_len(self->thread);
545 }
546 542
547 hist_entry_callchain__fprintf(fp, self, session_total, 543 if (sort__first_dimension == SORT_COMM) {
548 left_margin); 544 struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
545 typeof(*se), list);
546 left_margin = se->width ? *se->width : 0;
547 left_margin -= thread__comm_len(self->thread);
549 } 548 }
550 549
551 return ret; 550 return hist_entry_callchain__fprintf(fp, self, session_total,
551 left_margin);
552} 552}
553 553
554size_t perf_session__fprintf_hists(struct rb_root *hists, 554size_t perf_session__fprintf_hists(struct rb_root *hists,
@@ -655,6 +655,10 @@ print_entries:
655 } 655 }
656 ret += hist_entry__fprintf(h, pair, show_displacement, 656 ret += hist_entry__fprintf(h, pair, show_displacement,
657 displacement, fp, session_total); 657 displacement, fp, session_total);
658
659 if (symbol_conf.use_callchain)
660 ret += hist_entry__fprintf_callchain(h, fp, session_total);
661
658 if (h->map == NULL && verbose > 1) { 662 if (h->map == NULL && verbose > 1) {
659 __map_groups__fprintf_maps(&h->thread->mg, 663 __map_groups__fprintf_maps(&h->thread->mg,
660 MAP__FUNCTION, fp); 664 MAP__FUNCTION, fp);
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/include/linux/kernel.h b/tools/perf/util/include/linux/kernel.h
index f2611655ab51..388ab1bfd114 100644
--- a/tools/perf/util/include/linux/kernel.h
+++ b/tools/perf/util/include/linux/kernel.h
@@ -85,16 +85,19 @@ simple_strtoul(const char *nptr, char **endptr, int base)
85 return strtoul(nptr, endptr, base); 85 return strtoul(nptr, endptr, base);
86} 86}
87 87
88int eprintf(int level,
89 const char *fmt, ...) __attribute__((format(printf, 2, 3)));
90
88#ifndef pr_fmt 91#ifndef pr_fmt
89#define pr_fmt(fmt) fmt 92#define pr_fmt(fmt) fmt
90#endif 93#endif
91 94
92#define pr_err(fmt, ...) \ 95#define pr_err(fmt, ...) \
93 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0) 96 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
94#define pr_warning(fmt, ...) \ 97#define pr_warning(fmt, ...) \
95 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0) 98 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
96#define pr_info(fmt, ...) \ 99#define pr_info(fmt, ...) \
97 do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0) 100 eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
98#define pr_debug(fmt, ...) \ 101#define pr_debug(fmt, ...) \
99 eprintf(1, pr_fmt(fmt), ##__VA_ARGS__) 102 eprintf(1, pr_fmt(fmt), ##__VA_ARGS__)
100#define pr_debugN(n, fmt, ...) \ 103#define pr_debugN(n, fmt, ...) \
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c
new file mode 100644
index 000000000000..2d19e7a3e6e8
--- /dev/null
+++ b/tools/perf/util/newt.c
@@ -0,0 +1,207 @@
1#define _GNU_SOURCE
2#include <stdio.h>
3#undef _GNU_SOURCE
4
5#include <stdlib.h>
6#include <newt.h>
7#include <sys/ttydefaults.h>
8
9#include "cache.h"
10#include "hist.h"
11#include "session.h"
12#include "sort.h"
13#include "symbol.h"
14
15static void newt_form__set_exit_keys(newtComponent self)
16{
17 newtFormAddHotKey(self, NEWT_KEY_ESCAPE);
18 newtFormAddHotKey(self, 'Q');
19 newtFormAddHotKey(self, 'q');
20 newtFormAddHotKey(self, CTRL('c'));
21}
22
23static newtComponent newt_form__new(void)
24{
25 newtComponent self = newtForm(NULL, NULL, 0);
26 if (self)
27 newt_form__set_exit_keys(self);
28 return self;
29}
30
31static size_t hist_entry__append_browser(struct hist_entry *self,
32 newtComponent listbox, u64 total)
33{
34 char bf[1024];
35 size_t len;
36 FILE *fp;
37
38 if (symbol_conf.exclude_other && !self->parent)
39 return 0;
40
41 fp = fmemopen(bf, sizeof(bf), "w");
42 if (fp == NULL)
43 return 0;
44
45 len = hist_entry__fprintf(self, NULL, false, 0, fp, total);
46
47 fclose(fp);
48 newtListboxAppendEntry(listbox, bf, self);
49 return len;
50}
51
52static void hist_entry__annotate_browser(struct hist_entry *self)
53{
54 FILE *fp;
55 int cols, rows;
56 newtComponent form, listbox;
57 struct newtExitStruct es;
58 char *str;
59 size_t line_len, max_line_len = 0;
60 size_t max_usable_width;
61 char *line = NULL;
62
63 if (self->sym == NULL)
64 return;
65
66 if (asprintf(&str, "perf annotate %s 2>&1 | expand", self->sym->name) < 0)
67 return;
68
69 fp = popen(str, "r");
70 if (fp == NULL)
71 goto out_free_str;
72
73 newtPushHelpLine("Press ESC to exit");
74 newtGetScreenSize(&cols, &rows);
75 listbox = newtListbox(0, 0, rows - 5, NEWT_FLAG_SCROLL);
76
77 while (!feof(fp)) {
78 if (getline(&line, &line_len, fp) < 0 || !line_len)
79 break;
80 while (line_len != 0 && isspace(line[line_len - 1]))
81 line[--line_len] = '\0';
82
83 if (line_len > max_line_len)
84 max_line_len = line_len;
85 newtListboxAppendEntry(listbox, line, NULL);
86 }
87 fclose(fp);
88 free(line);
89
90 max_usable_width = cols - 22;
91 if (max_line_len > max_usable_width)
92 max_line_len = max_usable_width;
93
94 newtListboxSetWidth(listbox, max_line_len);
95
96 newtCenteredWindow(max_line_len + 2, rows - 5, self->sym->name);
97 form = newt_form__new();
98 newtFormAddComponents(form, listbox, NULL);
99
100 newtFormRun(form, &es);
101 newtFormDestroy(form);
102 newtPopWindow();
103 newtPopHelpLine();
104out_free_str:
105 free(str);
106}
107
108void perf_session__browse_hists(struct rb_root *hists, u64 session_total,
109 const char *helpline)
110{
111 struct sort_entry *se;
112 struct rb_node *nd;
113 unsigned int width;
114 char *col_width = symbol_conf.col_width_list_str;
115 int rows;
116 size_t max_len = 0;
117 char str[1024];
118 newtComponent form, listbox;
119 struct newtExitStruct es;
120
121 snprintf(str, sizeof(str), "Samples: %Ld", session_total);
122 newtDrawRootText(0, 0, str);
123 newtPushHelpLine(helpline);
124
125 newtGetScreenSize(NULL, &rows);
126
127 form = newt_form__new();
128
129 listbox = newtListbox(1, 1, rows - 2, (NEWT_FLAG_SCROLL |
130 NEWT_FLAG_BORDER |
131 NEWT_FLAG_RETURNEXIT));
132
133 list_for_each_entry(se, &hist_entry__sort_list, list) {
134 if (se->elide)
135 continue;
136 width = strlen(se->header);
137 if (se->width) {
138 if (symbol_conf.col_width_list_str) {
139 if (col_width) {
140 *se->width = atoi(col_width);
141 col_width = strchr(col_width, ',');
142 if (col_width)
143 ++col_width;
144 }
145 }
146 *se->width = max(*se->width, width);
147 }
148 }
149
150 for (nd = rb_first(hists); nd; nd = rb_next(nd)) {
151 struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
152 size_t len = hist_entry__append_browser(h, listbox, session_total);
153 if (len > max_len)
154 max_len = len;
155 }
156
157 newtListboxSetWidth(listbox, max_len);
158 newtFormAddComponents(form, listbox, NULL);
159
160 while (1) {
161 struct hist_entry *selection;
162
163 newtFormRun(form, &es);
164 if (es.reason == NEWT_EXIT_HOTKEY)
165 break;
166 selection = newtListboxGetCurrent(listbox);
167 hist_entry__annotate_browser(selection);
168 }
169
170 newtFormDestroy(form);
171}
172
173int browser__show_help(const char *format, va_list ap)
174{
175 int ret;
176 static int backlog;
177 static char msg[1024];
178
179 ret = vsnprintf(msg + backlog, sizeof(msg) - backlog, format, ap);
180 backlog += ret;
181
182 if (msg[backlog - 1] == '\n') {
183 newtPopHelpLine();
184 newtPushHelpLine(msg);
185 newtRefresh();
186 backlog = 0;
187 }
188
189 return ret;
190}
191
192void setup_browser(void)
193{
194 if (!isatty(1))
195 return;
196
197 use_browser = true;
198 newtInit();
199 newtCls();
200 newtPushHelpLine(" ");
201}
202
203void exit_browser(void)
204{
205 if (use_browser)
206 newtFinished();
207}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 05d0c5c2030c..a2014459125a 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -656,6 +656,10 @@ parse_raw_event(const char **strp, struct perf_event_attr *attr)
656 return EVT_FAILED; 656 return EVT_FAILED;
657 n = hex2u64(str + 1, &config); 657 n = hex2u64(str + 1, &config);
658 if (n > 0) { 658 if (n > 0) {
659 if (str[n+1] == 'p') {
660 attr->precise = 1;
661 n++;
662 }
659 *strp = str + n + 1; 663 *strp = str + n + 1;
660 attr->type = PERF_TYPE_RAW; 664 attr->type = PERF_TYPE_RAW;
661 attr->config = config; 665 attr->config = config;
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 */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index c458c4a371d1..3eb9de4baef3 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -18,18 +18,6 @@
18#define NT_GNU_BUILD_ID 3 18#define NT_GNU_BUILD_ID 3
19#endif 19#endif
20 20
21enum dso_origin {
22 DSO__ORIG_KERNEL = 0,
23 DSO__ORIG_JAVA_JIT,
24 DSO__ORIG_BUILD_ID_CACHE,
25 DSO__ORIG_FEDORA,
26 DSO__ORIG_UBUNTU,
27 DSO__ORIG_BUILDID,
28 DSO__ORIG_DSO,
29 DSO__ORIG_KMODULE,
30 DSO__ORIG_NOT_FOUND,
31};
32
33static void dsos__add(struct list_head *head, struct dso *dso); 21static void dsos__add(struct list_head *head, struct dso *dso);
34static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); 22static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
35static int dso__load_kernel_sym(struct dso *self, struct map *map, 23static int dso__load_kernel_sym(struct dso *self, struct map *map,
@@ -870,8 +858,8 @@ out_close:
870 if (err == 0) 858 if (err == 0)
871 return nr; 859 return nr;
872out: 860out:
873 pr_warning("%s: problems reading %s PLT info.\n", 861 pr_debug("%s: problems reading %s PLT info.\n",
874 __func__, self->long_name); 862 __func__, self->long_name);
875 return 0; 863 return 0;
876} 864}
877 865
@@ -1025,7 +1013,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
1025 } 1013 }
1026 curr_map->map_ip = identity__map_ip; 1014 curr_map->map_ip = identity__map_ip;
1027 curr_map->unmap_ip = identity__map_ip; 1015 curr_map->unmap_ip = identity__map_ip;
1028 curr_dso->origin = DSO__ORIG_KERNEL; 1016 curr_dso->origin = self->origin;
1029 map_groups__insert(kmap->kmaps, curr_map); 1017 map_groups__insert(kmap->kmaps, curr_map);
1030 dsos__add(&dsos__kernel, curr_dso); 1018 dsos__add(&dsos__kernel, curr_dso);
1031 dso__set_loaded(curr_dso, map->type); 1019 dso__set_loaded(curr_dso, map->type);
@@ -1895,6 +1883,17 @@ out_fail:
1895 return -1; 1883 return -1;
1896} 1884}
1897 1885
1886size_t vmlinux_path__fprintf(FILE *fp)
1887{
1888 int i;
1889 size_t printed = 0;
1890
1891 for (i = 0; i < vmlinux_path__nr_entries; ++i)
1892 printed += fprintf(fp, "[%d] %s\n", i, vmlinux_path[i]);
1893
1894 return printed;
1895}
1896
1898static int setup_list(struct strlist **list, const char *list_str, 1897static int setup_list(struct strlist **list, const char *list_str,
1899 const char *list_name) 1898 const char *list_name)
1900{ 1899{
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index f30a37428919..0da2455d5b90 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -106,6 +106,7 @@ struct dso {
106 u8 has_build_id:1; 106 u8 has_build_id:1;
107 u8 kernel:1; 107 u8 kernel:1;
108 u8 hit:1; 108 u8 hit:1;
109 u8 annotate_warned:1;
109 unsigned char origin; 110 unsigned char origin;
110 u8 sorted_by_name; 111 u8 sorted_by_name;
111 u8 loaded; 112 u8 loaded;
@@ -150,6 +151,19 @@ size_t dsos__fprintf_buildid(FILE *fp, bool with_hits);
150 151
151size_t dso__fprintf_buildid(struct dso *self, FILE *fp); 152size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
152size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp); 153size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
154
155enum dso_origin {
156 DSO__ORIG_KERNEL = 0,
157 DSO__ORIG_JAVA_JIT,
158 DSO__ORIG_BUILD_ID_CACHE,
159 DSO__ORIG_FEDORA,
160 DSO__ORIG_UBUNTU,
161 DSO__ORIG_BUILDID,
162 DSO__ORIG_DSO,
163 DSO__ORIG_KMODULE,
164 DSO__ORIG_NOT_FOUND,
165};
166
153char dso__symtab_origin(const struct dso *self); 167char dso__symtab_origin(const struct dso *self);
154void dso__set_long_name(struct dso *self, char *name); 168void dso__set_long_name(struct dso *self, char *name);
155void dso__set_build_id(struct dso *self, void *build_id); 169void dso__set_build_id(struct dso *self, void *build_id);
@@ -169,4 +183,6 @@ int kallsyms__parse(const char *filename, void *arg,
169int symbol__init(void); 183int symbol__init(void);
170bool symbol_type__is_a(char symbol_type, enum map_type map_type); 184bool symbol_type__is_a(char symbol_type, enum map_type map_type);
171 185
186size_t vmlinux_path__fprintf(FILE *fp);
187
172#endif /* __PERF_SYMBOL */ 188#endif /* __PERF_SYMBOL */