summaryrefslogtreecommitdiffstats
path: root/tools/perf/util
diff options
context:
space:
mode:
Diffstat (limited to 'tools/perf/util')
-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
12 files changed, 320 insertions, 45 deletions
diff --git a/tools/perf/util/cache.h b/tools/perf/util/cache.h
index 918eb376abe..47b12a3d11b 100644
--- a/tools/perf/util/cache.h
+++ b/tools/perf/util/cache.h
@@ -1,6 +1,7 @@
#ifndef __PERF_CACHE_H
#define __PERF_CACHE_H
+#include <stdbool.h>
#include "util.h"
#include "strbuf.h"
#include "../perf.h"
@@ -69,6 +70,19 @@ extern const char *pager_program;
extern int pager_in_use(void);
extern int pager_use_color;
+extern bool use_browser;
+
+#ifdef NO_NEWT_SUPPORT
+static inline void setup_browser(void)
+{
+ setup_pager();
+}
+static inline void exit_browser(void) {}
+#else
+void setup_browser(void);
+void exit_browser(void);
+#endif
+
extern const char *editor_program;
extern const char *excludes_file;
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index e88bca55a59..9da01914e0a 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, ...)
int r;
va_start(args, fmt);
- r = color_vfprintf(fp, color, fmt, args);
+ if (use_browser)
+ r = vfprintf(fp, fmt, args);
+ else
+ r = color_vfprintf(fp, color, fmt, args);
va_end(args);
return r;
}
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index 0905600c385..033d66db863 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -6,6 +6,7 @@
#include <stdarg.h>
#include <stdio.h>
+#include "cache.h"
#include "color.h"
#include "event.h"
#include "debug.h"
@@ -21,7 +22,10 @@ int eprintf(int level, const char *fmt, ...)
if (verbose >= level) {
va_start(args, fmt);
- ret = vfprintf(stderr, fmt, args);
+ if (use_browser)
+ ret = browser__show_help(fmt, args);
+ else
+ ret = vfprintf(stderr, fmt, args);
va_end(args);
}
diff --git a/tools/perf/util/debug.h b/tools/perf/util/debug.h
index c6c24c522de..0172edf3f15 100644
--- a/tools/perf/util/debug.h
+++ b/tools/perf/util/debug.h
@@ -7,9 +7,16 @@
extern int verbose;
extern int dump_trace;
-int eprintf(int level,
- const char *fmt, ...) __attribute__((format(printf, 2, 3)));
int dump_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
void trace_event(event_t *event);
+#ifdef NO_NEWT_SUPPORT
+static inline int browser__show_help(const char *format __used, va_list ap __used)
+{
+ return 0;
+}
+#else
+int browser__show_help(const char *format, va_list ap);
+#endif
+
#endif /* __PERF_DEBUG_H */
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index bdcfd6190b2..1a4e8376d84 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,
return ret;
}
-static size_t hist_entry__fprintf(struct hist_entry *self,
- struct perf_session *pair_session,
- bool show_displacement,
- long displacement, FILE *fp,
- u64 session_total)
+size_t hist_entry__fprintf(struct hist_entry *self,
+ struct perf_session *pair_session,
+ bool show_displacement,
+ long displacement, FILE *fp,
+ u64 session_total)
{
struct sort_entry *se;
u64 count, total;
@@ -485,9 +485,9 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
if (symbol_conf.show_nr_samples) {
if (sep)
- fprintf(fp, "%c%lld", *sep, count);
+ ret += fprintf(fp, "%c%lld", *sep, count);
else
- fprintf(fp, "%11lld", count);
+ ret += fprintf(fp, "%11lld", count);
}
if (pair_session) {
@@ -518,9 +518,9 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
snprintf(bf, sizeof(bf), " ");
if (sep)
- fprintf(fp, "%c%s", *sep, bf);
+ ret += fprintf(fp, "%c%s", *sep, bf);
else
- fprintf(fp, "%6.6s", bf);
+ ret += fprintf(fp, "%6.6s", bf);
}
}
@@ -528,27 +528,27 @@ static size_t hist_entry__fprintf(struct hist_entry *self,
if (se->elide)
continue;
- fprintf(fp, "%s", sep ?: " ");
+ ret += fprintf(fp, "%s", sep ?: " ");
ret += se->print(fp, self, se->width ? *se->width : 0);
}
- ret += fprintf(fp, "\n");
-
- if (symbol_conf.use_callchain) {
- int left_margin = 0;
+ return ret + fprintf(fp, "\n");
+}
- if (sort__first_dimension == SORT_COMM) {
- se = list_first_entry(&hist_entry__sort_list, typeof(*se),
- list);
- left_margin = se->width ? *se->width : 0;
- left_margin -= thread__comm_len(self->thread);
- }
+static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
+ u64 session_total)
+{
+ int left_margin = 0;
- hist_entry_callchain__fprintf(fp, self, session_total,
- left_margin);
+ if (sort__first_dimension == SORT_COMM) {
+ struct sort_entry *se = list_first_entry(&hist_entry__sort_list,
+ typeof(*se), list);
+ left_margin = se->width ? *se->width : 0;
+ left_margin -= thread__comm_len(self->thread);
}
- return ret;
+ return hist_entry_callchain__fprintf(fp, self, session_total,
+ left_margin);
}
size_t perf_session__fprintf_hists(struct rb_root *hists,
@@ -655,6 +655,10 @@ print_entries:
}
ret += hist_entry__fprintf(h, pair, show_displacement,
displacement, fp, session_total);
+
+ if (symbol_conf.use_callchain)
+ ret += hist_entry__fprintf_callchain(h, fp, session_total);
+
if (h->map == NULL && verbose > 1) {
__map_groups__fprintf_maps(&h->thread->mg,
MAP__FUNCTION, fp);
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 16f360cce5b..fe366ce5db4 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,
u64 count, bool *hit);
extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
+size_t hist_entry__fprintf(struct hist_entry *self,
+ struct perf_session *pair_session,
+ bool show_displacement,
+ long displacement, FILE *fp,
+ u64 session_total);
void hist_entry__free(struct hist_entry *);
void 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 f2611655ab5..388ab1bfd11 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)
return strtoul(nptr, endptr, base);
}
+int eprintf(int level,
+ const char *fmt, ...) __attribute__((format(printf, 2, 3)));
+
#ifndef pr_fmt
#define pr_fmt(fmt) fmt
#endif
#define pr_err(fmt, ...) \
- do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
+ eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
#define pr_warning(fmt, ...) \
- do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
+ eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
#define pr_info(fmt, ...) \
- do { fprintf(stderr, pr_fmt(fmt), ##__VA_ARGS__); } while (0)
+ eprintf(0, pr_fmt(fmt), ##__VA_ARGS__)
#define pr_debug(fmt, ...) \
eprintf(1, pr_fmt(fmt), ##__VA_ARGS__)
#define pr_debugN(n, fmt, ...) \
diff --git a/tools/perf/util/newt.c b/tools/perf/util/newt.c
new file mode 100644
index 00000000000..2d19e7a3e6e
--- /dev/null
+++ b/tools/perf/util/newt.c
@@ -0,0 +1,207 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#undef _GNU_SOURCE
+
+#include <stdlib.h>
+#include <newt.h>
+#include <sys/ttydefaults.h>
+
+#include "cache.h"
+#include "hist.h"
+#include "session.h"
+#include "sort.h"
+#include "symbol.h"
+
+static void newt_form__set_exit_keys(newtComponent self)
+{
+ newtFormAddHotKey(self, NEWT_KEY_ESCAPE);
+ newtFormAddHotKey(self, 'Q');
+ newtFormAddHotKey(self, 'q');
+ newtFormAddHotKey(self, CTRL('c'));
+}
+
+static newtComponent newt_form__new(void)
+{
+ newtComponent self = newtForm(NULL, NULL, 0);
+ if (self)
+ newt_form__set_exit_keys(self);
+ return self;
+}
+
+static size_t hist_entry__append_browser(struct hist_entry *self,
+ newtComponent listbox, u64 total)
+{
+ char bf[1024];
+ size_t len;
+ FILE *fp;
+
+ if (symbol_conf.exclude_other && !self->parent)
+ return 0;
+
+ fp = fmemopen(bf, sizeof(bf), "w");
+ if (fp == NULL)
+ return 0;
+
+ len = hist_entry__fprintf(self, NULL, false, 0, fp, total);
+
+ fclose(fp);
+ newtListboxAppendEntry(listbox, bf, self);
+ return len;
+}
+
+static void hist_entry__annotate_browser(struct hist_entry *self)
+{
+ FILE *fp;
+ int cols, rows;
+ newtComponent form, listbox;
+ struct newtExitStruct es;
+ char *str;
+ size_t line_len, max_line_len = 0;
+ size_t max_usable_width;
+ char *line = NULL;
+
+ if (self->sym == NULL)
+ return;
+
+ if (asprintf(&str, "perf annotate %s 2>&1 | expand", self->sym->name) < 0)
+ return;
+
+ fp = popen(str, "r");
+ if (fp == NULL)
+ goto out_free_str;
+
+ newtPushHelpLine("Press ESC to exit");
+ newtGetScreenSize(&cols, &rows);
+ listbox = newtListbox(0, 0, rows - 5, NEWT_FLAG_SCROLL);
+
+ while (!feof(fp)) {
+ if (getline(&line, &line_len, fp) < 0 || !line_len)
+ break;
+ while (line_len != 0 && isspace(line[line_len - 1]))
+ line[--line_len] = '\0';
+
+ if (line_len > max_line_len)
+ max_line_len = line_len;
+ newtListboxAppendEntry(listbox, line, NULL);
+ }
+ fclose(fp);
+ free(line);
+
+ max_usable_width = cols - 22;
+ if (max_line_len > max_usable_width)
+ max_line_len = max_usable_width;
+
+ newtListboxSetWidth(listbox, max_line_len);
+
+ newtCenteredWindow(max_line_len + 2, rows - 5, self->sym->name);
+ form = newt_form__new();
+ newtFormAddComponents(form, listbox, NULL);
+
+ newtFormRun(form, &es);
+ newtFormDestroy(form);
+ newtPopWindow();
+ newtPopHelpLine();
+out_free_str:
+ free(str);
+}
+
+void perf_session__browse_hists(struct rb_root *hists, u64 session_total,
+ const char *helpline)
+{
+ struct sort_entry *se;
+ struct rb_node *nd;
+ unsigned int width;
+ char *col_width = symbol_conf.col_width_list_str;
+ int rows;
+ size_t max_len = 0;
+ char str[1024];
+ newtComponent form, listbox;
+ struct newtExitStruct es;
+
+ snprintf(str, sizeof(str), "Samples: %Ld", session_total);
+ newtDrawRootText(0, 0, str);
+ newtPushHelpLine(helpline);
+
+ newtGetScreenSize(NULL, &rows);
+
+ form = newt_form__new();
+
+ listbox = newtListbox(1, 1, rows - 2, (NEWT_FLAG_SCROLL |
+ NEWT_FLAG_BORDER |
+ NEWT_FLAG_RETURNEXIT));
+
+ list_for_each_entry(se, &hist_entry__sort_list, list) {
+ if (se->elide)
+ continue;
+ width = strlen(se->header);
+ if (se->width) {
+ if (symbol_conf.col_width_list_str) {
+ if (col_width) {
+ *se->width = atoi(col_width);
+ col_width = strchr(col_width, ',');
+ if (col_width)
+ ++col_width;
+ }
+ }
+ *se->width = max(*se->width, width);
+ }
+ }
+
+ for (nd = rb_first(hists); nd; nd = rb_next(nd)) {
+ struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+ size_t len = hist_entry__append_browser(h, listbox, session_total);
+ if (len > max_len)
+ max_len = len;
+ }
+
+ newtListboxSetWidth(listbox, max_len);
+ newtFormAddComponents(form, listbox, NULL);
+
+ while (1) {
+ struct hist_entry *selection;
+
+ newtFormRun(form, &es);
+ if (es.reason == NEWT_EXIT_HOTKEY)
+ break;
+ selection = newtListboxGetCurrent(listbox);
+ hist_entry__annotate_browser(selection);
+ }
+
+ newtFormDestroy(form);
+}
+
+int browser__show_help(const char *format, va_list ap)
+{
+ int ret;
+ static int backlog;
+ static char msg[1024];
+
+ ret = vsnprintf(msg + backlog, sizeof(msg) - backlog, format, ap);
+ backlog += ret;
+
+ if (msg[backlog - 1] == '\n') {
+ newtPopHelpLine();
+ newtPushHelpLine(msg);
+ newtRefresh();
+ backlog = 0;
+ }
+
+ return ret;
+}
+
+void setup_browser(void)
+{
+ if (!isatty(1))
+ return;
+
+ use_browser = true;
+ newtInit();
+ newtCls();
+ newtPushHelpLine(" ");
+}
+
+void exit_browser(void)
+{
+ if (use_browser)
+ newtFinished();
+}
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index 05d0c5c2030..a2014459125 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)
return EVT_FAILED;
n = hex2u64(str + 1, &config);
if (n > 0) {
+ if (str[n+1] == 'p') {
+ attr->precise = 1;
+ n++;
+ }
*strp = str + n + 1;
attr->type = PERF_TYPE_RAW;
attr->config = config;
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 5c33417eebb..34d73395baa 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -86,4 +86,13 @@ static inline struct map *
{
return map_groups__new_module(&self->kmaps, start, filename);
}
+
+#ifdef NO_NEWT_SUPPORT
+static inline void perf_session__browse_hists(struct rb_root *hists __used,
+ u64 session_total __used,
+ const char *helpline __used) {}
+#else
+void perf_session__browse_hists(struct rb_root *hists, u64 session_total,
+ const char *helpline);
+#endif
#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index c458c4a371d..3eb9de4baef 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -18,18 +18,6 @@
#define NT_GNU_BUILD_ID 3
#endif
-enum dso_origin {
- DSO__ORIG_KERNEL = 0,
- DSO__ORIG_JAVA_JIT,
- DSO__ORIG_BUILD_ID_CACHE,
- DSO__ORIG_FEDORA,
- DSO__ORIG_UBUNTU,
- DSO__ORIG_BUILDID,
- DSO__ORIG_DSO,
- DSO__ORIG_KMODULE,
- DSO__ORIG_NOT_FOUND,
-};
-
static void dsos__add(struct list_head *head, struct dso *dso);
static struct map *map__new2(u64 start, struct dso *dso, enum map_type type);
static int dso__load_kernel_sym(struct dso *self, struct map *map,
@@ -870,8 +858,8 @@ out_close:
if (err == 0)
return nr;
out:
- pr_warning("%s: problems reading %s PLT info.\n",
- __func__, self->long_name);
+ pr_debug("%s: problems reading %s PLT info.\n",
+ __func__, self->long_name);
return 0;
}
@@ -1025,7 +1013,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name,
}
curr_map->map_ip = identity__map_ip;
curr_map->unmap_ip = identity__map_ip;
- curr_dso->origin = DSO__ORIG_KERNEL;
+ curr_dso->origin = self->origin;
map_groups__insert(kmap->kmaps, curr_map);
dsos__add(&dsos__kernel, curr_dso);
dso__set_loaded(curr_dso, map->type);
@@ -1895,6 +1883,17 @@ out_fail:
return -1;
}
+size_t vmlinux_path__fprintf(FILE *fp)
+{
+ int i;
+ size_t printed = 0;
+
+ for (i = 0; i < vmlinux_path__nr_entries; ++i)
+ printed += fprintf(fp, "[%d] %s\n", i, vmlinux_path[i]);
+
+ return printed;
+}
+
static int setup_list(struct strlist **list, const char *list_str,
const char *list_name)
{
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index f30a3742891..0da2455d5b9 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -106,6 +106,7 @@ struct dso {
u8 has_build_id:1;
u8 kernel:1;
u8 hit:1;
+ u8 annotate_warned:1;
unsigned char origin;
u8 sorted_by_name;
u8 loaded;
@@ -150,6 +151,19 @@ size_t dsos__fprintf_buildid(FILE *fp, bool with_hits);
size_t dso__fprintf_buildid(struct dso *self, FILE *fp);
size_t dso__fprintf(struct dso *self, enum map_type type, FILE *fp);
+
+enum dso_origin {
+ DSO__ORIG_KERNEL = 0,
+ DSO__ORIG_JAVA_JIT,
+ DSO__ORIG_BUILD_ID_CACHE,
+ DSO__ORIG_FEDORA,
+ DSO__ORIG_UBUNTU,
+ DSO__ORIG_BUILDID,
+ DSO__ORIG_DSO,
+ DSO__ORIG_KMODULE,
+ DSO__ORIG_NOT_FOUND,
+};
+
char dso__symtab_origin(const struct dso *self);
void dso__set_long_name(struct dso *self, char *name);
void dso__set_build_id(struct dso *self, void *build_id);
@@ -169,4 +183,6 @@ int kallsyms__parse(const char *filename, void *arg,
int symbol__init(void);
bool symbol_type__is_a(char symbol_type, enum map_type map_type);
+size_t vmlinux_path__fprintf(FILE *fp);
+
#endif /* __PERF_SYMBOL */