summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tools/perf/builtin-diff.c2
-rw-r--r--tools/perf/builtin-help.c2
-rw-r--r--tools/perf/builtin-kmem.c4
-rw-r--r--tools/perf/builtin-report.c2
-rw-r--r--tools/perf/builtin-script.c21
-rw-r--r--tools/perf/builtin-top.c4
-rw-r--r--tools/perf/builtin-trace.c46
-rw-r--r--tools/perf/jvmti/Makefile17
-rw-r--r--tools/perf/perf.c16
-rw-r--r--tools/perf/tests/llvm.c8
-rw-r--r--tools/perf/ui/browsers/hists.c128
-rw-r--r--tools/perf/ui/gtk/hists.c11
-rw-r--r--tools/perf/ui/hist.c22
-rw-r--r--tools/perf/ui/stdio/hist.c49
-rw-r--r--tools/perf/util/color.c5
-rw-r--r--tools/perf/util/data-convert-bt.c2
-rw-r--r--tools/perf/util/evlist.c3
-rw-r--r--tools/perf/util/help-unknown-cmd.c5
-rw-r--r--tools/perf/util/hist.c48
-rw-r--r--tools/perf/util/hist.h4
-rw-r--r--tools/perf/util/parse-events.y6
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c3
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c3
-rw-r--r--tools/perf/util/sort.c30
-rw-r--r--tools/perf/util/sort.h1
25 files changed, 363 insertions, 79 deletions
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 36ccc2b8827f..4d72359fd15a 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -1264,8 +1264,6 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
if (ret < 0)
return ret;
- perf_config(perf_default_config, NULL);
-
argc = parse_options(argc, argv, options, diff_usage, 0);
if (symbol__init(NULL) < 0)
diff --git a/tools/perf/builtin-help.c b/tools/perf/builtin-help.c
index f4dd2b48f90f..49d55e21b1b0 100644
--- a/tools/perf/builtin-help.c
+++ b/tools/perf/builtin-help.c
@@ -272,7 +272,7 @@ static int perf_help_config(const char *var, const char *value, void *cb)
if (!prefixcmp(var, "man."))
return add_man_viewer_info(var, value);
- return perf_default_config(var, value, cb);
+ return 0;
}
static struct cmdnames main_cmds, other_cmds;
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c
index 118010553d0c..4d3340cce9a0 100644
--- a/tools/perf/builtin-kmem.c
+++ b/tools/perf/builtin-kmem.c
@@ -1834,7 +1834,7 @@ static int __cmd_record(int argc, const char **argv)
return cmd_record(i, rec_argv, NULL);
}
-static int kmem_config(const char *var, const char *value, void *cb)
+static int kmem_config(const char *var, const char *value, void *cb __maybe_unused)
{
if (!strcmp(var, "kmem.default")) {
if (!strcmp(value, "slab"))
@@ -1847,7 +1847,7 @@ static int kmem_config(const char *var, const char *value, void *cb)
return 0;
}
- return perf_default_config(var, value, cb);
+ return 0;
}
int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index f4d8244449ca..7eea49f9ed46 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -90,7 +90,7 @@ static int report__config(const char *var, const char *value, void *cb)
return 0;
}
- return perf_default_config(var, value, cb);
+ return 0;
}
static int hist_iter__report_callback(struct hist_entry_iter *iter,
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index ec4fbd410a4b..57f9a7e7f7d3 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -1212,23 +1212,6 @@ static struct script_spec *script_spec__find(const char *spec)
return NULL;
}
-static struct script_spec *script_spec__findnew(const char *spec,
- struct scripting_ops *ops)
-{
- struct script_spec *s = script_spec__find(spec);
-
- if (s)
- return s;
-
- s = script_spec__new(spec, ops);
- if (!s)
- return NULL;
-
- script_spec__add(s);
-
- return s;
-}
-
int script_spec_register(const char *spec, struct scripting_ops *ops)
{
struct script_spec *s;
@@ -1237,9 +1220,11 @@ int script_spec_register(const char *spec, struct scripting_ops *ops)
if (s)
return -1;
- s = script_spec__findnew(spec, ops);
+ s = script_spec__new(spec, ops);
if (!s)
return -1;
+ else
+ script_spec__add(s);
return 0;
}
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index b86b623e8799..94af190f6843 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -1065,7 +1065,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
return parse_callchain_top_opt(arg);
}
-static int perf_top_config(const char *var, const char *value, void *cb)
+static int perf_top_config(const char *var, const char *value, void *cb __maybe_unused)
{
if (!strcmp(var, "top.call-graph"))
var = "call-graph.record-mode"; /* fall-through */
@@ -1074,7 +1074,7 @@ static int perf_top_config(const char *var, const char *value, void *cb)
return 0;
}
- return perf_default_config(var, value, cb);
+ return 0;
}
static int
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index 20916dd77aac..26a337f939d8 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -33,6 +33,7 @@
#include "util/stat.h"
#include "trace-event.h"
#include "util/parse-events.h"
+#include "util/bpf-loader.h"
#include <libaudit.h>
#include <stdlib.h>
@@ -2177,6 +2178,37 @@ out_dump:
return 0;
}
+static void bpf_output__printer(enum binary_printer_ops op,
+ unsigned int val, void *extra)
+{
+ FILE *output = extra;
+ unsigned char ch = (unsigned char)val;
+
+ switch (op) {
+ case BINARY_PRINT_CHAR_DATA:
+ fprintf(output, "%c", isprint(ch) ? ch : '.');
+ break;
+ case BINARY_PRINT_DATA_BEGIN:
+ case BINARY_PRINT_LINE_BEGIN:
+ case BINARY_PRINT_ADDR:
+ case BINARY_PRINT_NUM_DATA:
+ case BINARY_PRINT_NUM_PAD:
+ case BINARY_PRINT_SEP:
+ case BINARY_PRINT_CHAR_PAD:
+ case BINARY_PRINT_LINE_END:
+ case BINARY_PRINT_DATA_END:
+ default:
+ break;
+ }
+}
+
+static void bpf_output__fprintf(struct trace *trace,
+ struct perf_sample *sample)
+{
+ print_binary(sample->raw_data, sample->raw_size, 8,
+ bpf_output__printer, trace->output);
+}
+
static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
union perf_event *event __maybe_unused,
struct perf_sample *sample)
@@ -2189,7 +2221,9 @@ static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
fprintf(trace->output, "%s:", evsel->name);
- if (evsel->tp_format) {
+ if (perf_evsel__is_bpf_output(evsel)) {
+ bpf_output__fprintf(trace, sample);
+ } else if (evsel->tp_format) {
event_format__fprintf(evsel->tp_format, sample->cpu,
sample->raw_data, sample->raw_size,
trace->output);
@@ -2586,6 +2620,16 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
if (err < 0)
goto out_error_open;
+ err = bpf__apply_obj_config();
+ if (err) {
+ char errbuf[BUFSIZ];
+
+ bpf__strerror_apply_obj_config(err, errbuf, sizeof(errbuf));
+ pr_err("ERROR: Apply config to BPF failed: %s\n",
+ errbuf);
+ goto out_error_open;
+ }
+
/*
* Better not use !target__has_task() here because we need to cover the
* case where no threads were specified in the command line, but a
diff --git a/tools/perf/jvmti/Makefile b/tools/perf/jvmti/Makefile
index 0277a64b391b..5ce61a1bda9c 100644
--- a/tools/perf/jvmti/Makefile
+++ b/tools/perf/jvmti/Makefile
@@ -35,12 +35,21 @@ SOLIBEXT=so
# The following works at least on fedora 23, you may need the next
# line for other distros.
-ifeq (,$(wildcard /usr/sbin/update-java-alternatives))
-JDIR=$(shell alternatives --display java | tail -1 | cut -d' ' -f 5 | sed 's%/jre/bin/java.%%g')
-else
+ifneq (,$(wildcard /usr/sbin/update-java-alternatives))
JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | cut -d ' ' -f 3)
+else
+ ifneq (,$(wildcard /usr/sbin/alternatives))
+ JDIR=$(shell alternatives --display java | tail -1 | cut -d' ' -f 5 | sed 's%/jre/bin/java.%%g')
+ endif
endif
-
+ifndef JDIR
+$(error Could not find alternatives command, you need to set JDIR= to point to the root of your Java directory)
+else
+ ifeq (,$(wildcard $(JDIR)/include/jvmti.h))
+ $(error the openjdk development package appears to me missing, install and try again)
+ endif
+endif
+$(info Using Java from $(JDIR))
# -lrt required in 32-bit mode for clock_gettime()
LIBS=-lelf -lrt
INCDIR=-I $(JDIR)/include -I $(JDIR)/include/linux
diff --git a/tools/perf/perf.c b/tools/perf/perf.c
index 144047c396f0..aaee0a782747 100644
--- a/tools/perf/perf.c
+++ b/tools/perf/perf.c
@@ -454,11 +454,12 @@ static void handle_internal_command(int argc, const char **argv)
static void execv_dashed_external(const char **argv)
{
- struct strbuf cmd = STRBUF_INIT;
+ char *cmd;
const char *tmp;
int status;
- strbuf_addf(&cmd, "perf-%s", argv[0]);
+ if (asprintf(&cmd, "perf-%s", argv[0]) < 0)
+ goto do_die;
/*
* argv[0] must be the perf command, but the argv array
@@ -467,7 +468,7 @@ static void execv_dashed_external(const char **argv)
* restore it on error.
*/
tmp = argv[0];
- argv[0] = cmd.buf;
+ argv[0] = cmd;
/*
* if we fail because the command is not found, it is
@@ -475,15 +476,16 @@ static void execv_dashed_external(const char **argv)
*/
status = run_command_v_opt(argv, 0);
if (status != -ERR_RUN_COMMAND_EXEC) {
- if (IS_RUN_COMMAND_ERR(status))
+ if (IS_RUN_COMMAND_ERR(status)) {
+do_die:
die("unable to run '%s'", argv[0]);
+ }
exit(-status);
}
errno = ENOENT; /* as if we called execvp */
argv[0] = tmp;
-
- strbuf_release(&cmd);
+ zfree(&cmd);
}
static int run_argv(int *argcp, const char ***argv)
@@ -546,6 +548,8 @@ int main(int argc, const char **argv)
srandom(time(NULL));
+ perf_config(perf_default_config, NULL);
+
/* get debugfs/tracefs mount point from /proc/mounts */
tracing_path_mount();
diff --git a/tools/perf/tests/llvm.c b/tools/perf/tests/llvm.c
index 70edcdfa5672..cff564fb4b66 100644
--- a/tools/perf/tests/llvm.c
+++ b/tools/perf/tests/llvm.c
@@ -6,12 +6,6 @@
#include "tests.h"
#include "debug.h"
-static int perf_config_cb(const char *var, const char *val,
- void *arg __maybe_unused)
-{
- return perf_default_config(var, val, arg);
-}
-
#ifdef HAVE_LIBBPF_SUPPORT
static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz)
{
@@ -77,8 +71,6 @@ test_llvm__fetch_bpf_obj(void **p_obj_buf,
if (should_load_fail)
*should_load_fail = bpf_source_table[idx].should_load_fail;
- perf_config(perf_config_cb, NULL);
-
/*
* Skip this test if user's .perfconfig doesn't set [llvm] section
* and clang is not found in $PATH, and this is not perf test -v
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 6bcd7670ce5f..5ffffcb1e3c5 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -260,6 +260,9 @@ static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
if (he->leaf)
return callchain__count_rows(&he->sorted_chain);
+ if (he->has_no_entry)
+ return 1;
+
node = rb_first(&he->hroot_out);
while (node) {
float percent;
@@ -409,10 +412,18 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)
/* account grand children */
if (symbol_conf.report_hierarchy)
browser->b.nr_entries += child_rows - he->nr_rows;
+
+ if (!he->leaf && he->nr_rows == 0) {
+ he->has_no_entry = true;
+ he->nr_rows = 1;
+ }
} else {
if (symbol_conf.report_hierarchy)
browser->b.nr_entries -= child_rows - he->nr_rows;
+ if (he->has_no_entry)
+ he->has_no_entry = false;
+
he->nr_rows = 0;
}
@@ -545,6 +556,12 @@ __hist_browser__set_folding(struct hist_browser *browser, bool unfold)
browser->nr_hierarchy_entries++;
if (he->leaf)
browser->nr_callchain_rows += he->nr_rows;
+ else if (unfold && !hist_entry__has_hierarchy_children(he, browser->min_pcnt)) {
+ browser->nr_hierarchy_entries++;
+ he->has_no_entry = true;
+ he->nr_rows = 1;
+ } else
+ he->has_no_entry = false;
}
}
@@ -1383,8 +1400,13 @@ static int hist_browser__show_hierarchy_entry(struct hist_browser *browser,
if (fmt->color) {
width -= fmt->color(fmt, &hpp, entry);
} else {
+ int i = 0;
+
width -= fmt->entry(fmt, &hpp, entry);
- ui_browser__printf(&browser->b, "%s", s);
+ ui_browser__printf(&browser->b, "%s", ltrim(s));
+
+ while (isspace(s[i++]))
+ width++;
}
}
@@ -1412,6 +1434,75 @@ show_callchain:
return printed;
}
+static int hist_browser__show_no_entry(struct hist_browser *browser,
+ unsigned short row,
+ int level, int nr_sort_keys)
+{
+ int width = browser->b.width;
+ bool current_entry = ui_browser__is_current_entry(&browser->b, row);
+ bool first = true;
+ int column = 0;
+ int ret;
+ struct perf_hpp_fmt *fmt;
+
+ if (current_entry) {
+ browser->he_selection = NULL;
+ browser->selection = NULL;
+ }
+
+ hist_browser__gotorc(browser, row, 0);
+
+ if (current_entry && browser->b.navkeypressed)
+ ui_browser__set_color(&browser->b, HE_COLORSET_SELECTED);
+ else
+ ui_browser__set_color(&browser->b, HE_COLORSET_NORMAL);
+
+ ui_browser__write_nstring(&browser->b, "", level * HIERARCHY_INDENT);
+ width -= level * HIERARCHY_INDENT;
+
+ hists__for_each_format(browser->hists, fmt) {
+ if (perf_hpp__should_skip(fmt, browser->hists) ||
+ column++ < browser->b.horiz_scroll)
+ continue;
+
+ if (perf_hpp__is_sort_entry(fmt) ||
+ perf_hpp__is_dynamic_entry(fmt))
+ break;
+
+ ret = fmt->width(fmt, NULL, hists_to_evsel(browser->hists));
+
+ if (first) {
+ /* for folded sign */
+ first = false;
+ ret++;
+ } else {
+ /* space between columns */
+ ret += 2;
+ }
+
+ ui_browser__write_nstring(&browser->b, "", ret);
+ width -= ret;
+ }
+
+ ui_browser__write_nstring(&browser->b, "", nr_sort_keys * HIERARCHY_INDENT);
+ width -= nr_sort_keys * HIERARCHY_INDENT;
+
+ if (column >= browser->b.horiz_scroll) {
+ char buf[32];
+
+ ret = snprintf(buf, sizeof(buf), "no entry >= %.2f%%", browser->min_pcnt);
+ ui_browser__printf(&browser->b, " %s", buf);
+ width -= ret + 2;
+ }
+
+ /* The scroll bar isn't being used */
+ if (!browser->b.navkeypressed)
+ width += 1;
+
+ ui_browser__write_nstring(&browser->b, "", width);
+ return 1;
+}
+
static int advance_hpp_check(struct perf_hpp *hpp, int inc)
{
advance_hpp(hpp, inc);
@@ -1461,7 +1552,7 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
struct perf_hpp_fmt *fmt;
size_t ret = 0;
int column = 0;
- int nr_sort_keys = hists->hpp_list->nr_sort_keys;
+ int nr_sort_keys = hists->nr_sort_keys;
bool first = true;
ret = scnprintf(buf, size, " ");
@@ -1490,6 +1581,8 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
return ret;
hists__for_each_format(hists, fmt) {
+ char *start;
+
if (!perf_hpp__is_sort_entry(fmt) && !perf_hpp__is_dynamic_entry(fmt))
continue;
if (perf_hpp__should_skip(fmt, hists))
@@ -1507,7 +1600,12 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
dummy_hpp.buf[ret] = '\0';
rtrim(dummy_hpp.buf);
- ret = strlen(dummy_hpp.buf);
+ start = ltrim(dummy_hpp.buf);
+ ret = strlen(start);
+
+ if (start != dummy_hpp.buf)
+ memmove(dummy_hpp.buf, start, ret + 1);
+
if (advance_hpp_check(&dummy_hpp, ret))
break;
}
@@ -1546,7 +1644,7 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
u16 header_offset = 0;
struct rb_node *nd;
struct hist_browser *hb = container_of(browser, struct hist_browser, b);
- int nr_sort = hb->hists->hpp_list->nr_sort_keys;
+ int nr_sort = hb->hists->nr_sort_keys;
if (hb->show_headers) {
hist_browser__show_headers(hb);
@@ -1575,6 +1673,14 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
row += hist_browser__show_hierarchy_entry(hb, h, row,
h->depth,
nr_sort);
+ if (row == browser->rows)
+ break;
+
+ if (h->has_no_entry) {
+ hist_browser__show_no_entry(hb, row, h->depth,
+ nr_sort);
+ row++;
+ }
} else {
row += hist_browser__show_entry(hb, h, row);
}
@@ -1875,7 +1981,7 @@ static int hist_browser__fprintf(struct hist_browser *browser, FILE *fp)
struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
browser->min_pcnt);
int printed = 0;
- int nr_sort = browser->hists->hpp_list->nr_sort_keys;
+ int nr_sort = browser->hists->nr_sort_keys;
while (nd) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
@@ -2461,6 +2567,11 @@ static void hist_browser__update_percent_limit(struct hist_browser *hb,
while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
he = rb_entry(nd, struct hist_entry, rb_node);
+ if (he->has_no_entry) {
+ he->has_no_entry = false;
+ he->nr_rows = 0;
+ }
+
if (!he->leaf || !symbol_conf.use_callchain)
goto next;
@@ -2477,12 +2588,7 @@ static void hist_browser__update_percent_limit(struct hist_browser *hb,
min_callchain_hits, &callchain_param);
next:
- /*
- * Tentatively set unfolded so that the rb_hierarchy_next()
- * can toggle children of folded entries too.
- */
- he->unfolded = he->has_children;
- nd = rb_hierarchy_next(nd);
+ nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
/* force to re-evaluate folding state of callchains */
he->init_have_children = false;
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 7f343339eae7..a5758fdfbe1f 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -449,6 +449,17 @@ static void perf_gtk__add_hierarchy_entries(struct hists *hists,
perf_gtk__add_hierarchy_entries(hists, &he->hroot_out,
store, &iter, hpp,
min_pcnt);
+
+ if (!hist_entry__has_hierarchy_children(he, min_pcnt)) {
+ char buf[32];
+ GtkTreeIter child;
+
+ snprintf(buf, sizeof(buf), "no entry >= %.2f%%",
+ min_pcnt);
+
+ gtk_tree_store_append(store, &child, &iter);
+ gtk_tree_store_set(store, &child, col_idx, buf, -1);
+ }
}
if (symbol_conf.use_callchain && he->leaf) {
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index edbf854e8e1c..7c0585c146e1 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -643,6 +643,28 @@ unsigned int hists__sort_list_width(struct hists *hists)
return ret;
}
+unsigned int hists__overhead_width(struct hists *hists)
+{
+ struct perf_hpp_fmt *fmt;
+ int ret = 0;
+ bool first = true;
+ struct perf_hpp dummy_hpp;
+
+ hists__for_each_format(hists, fmt) {
+ if (perf_hpp__is_sort_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
+ break;
+
+ if (first)
+ first = false;
+ else
+ ret += 2;
+
+ ret += fmt->width(fmt, &dummy_hpp, hists_to_evsel(hists));
+ }
+
+ return ret;
+}
+
void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
{
if (perf_hpp__is_sort_entry(fmt))
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 435eaaaf2f1d..6d06fbb365b6 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -418,6 +418,7 @@ static int hist_entry__hierarchy_fprintf(struct hist_entry *he,
const char *sep = symbol_conf.field_sep;
struct perf_hpp_fmt *fmt;
char *buf = hpp->buf;
+ size_t size = hpp->size;
int ret, printed = 0;
bool first = true;
@@ -457,6 +458,11 @@ static int hist_entry__hierarchy_fprintf(struct hist_entry *he,
(nr_sort_key - 1) * HIERARCHY_INDENT + 2, "");
advance_hpp(hpp, ret);
+ printed += fprintf(fp, "%s", buf);
+
+ hpp->buf = buf;
+ hpp->size = size;
+
/*
* No need to call hist_entry__snprintf_alignment() since this
* fmt is always the last column in the hierarchy mode.
@@ -467,7 +473,11 @@ static int hist_entry__hierarchy_fprintf(struct hist_entry *he,
else
fmt->entry(fmt, hpp, he);
- printed += fprintf(fp, "%s\n", buf);
+ /*
+ * dynamic entries are right-aligned but we want left-aligned
+ * in the hierarchy mode
+ */
+ printed += fprintf(fp, "%s\n", ltrim(buf));
if (symbol_conf.use_callchain && he->leaf) {
u64 total = hists__total_period(hists);
@@ -495,7 +505,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
size = hpp.size = bfsz;
if (symbol_conf.report_hierarchy) {
- int nr_sort = hists->hpp_list->nr_sort_keys;
+ int nr_sort = hists->nr_sort_keys;
return hist_entry__hierarchy_fprintf(he, &hpp, nr_sort,
hists, fp);
@@ -525,11 +535,12 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
{
bool first = true;
int nr_sort;
+ int depth;
unsigned width = 0;
unsigned header_width = 0;
struct perf_hpp_fmt *fmt;
- nr_sort = hists->hpp_list->nr_sort_keys;
+ nr_sort = hists->nr_sort_keys;
/* preserve max indent depth for column headers */
print_hierarchy_indent(sep, nr_sort, spaces, fp);
@@ -558,19 +569,16 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
if (!first)
header_width += fprintf(fp, " / ");
else {
- header_width += fprintf(fp, "%s", sep ?: " ");
+ fprintf(fp, "%s", sep ?: " ");
first = false;
}
fmt->header(fmt, hpp, hists_to_evsel(hists));
rtrim(hpp->buf);
- header_width += fprintf(fp, "%s", hpp->buf);
+ header_width += fprintf(fp, "%s", ltrim(hpp->buf));
}
- /* preserve max indent depth for combined sort headers */
- print_hierarchy_indent(sep, nr_sort, spaces, fp);
-
fprintf(fp, "\n# ");
/* preserve max indent depth for initial dots */
@@ -590,6 +598,7 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
fprintf(fp, "%.*s", width, dots);
}
+ depth = 0;
hists__for_each_format(hists, fmt) {
if (!perf_hpp__is_sort_entry(fmt) && !perf_hpp__is_dynamic_entry(fmt))
continue;
@@ -597,15 +606,16 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
continue;
width = fmt->width(fmt, hpp, hists_to_evsel(hists));
+ width += depth * HIERARCHY_INDENT;
+
if (width > header_width)
header_width = width;
+
+ depth++;
}
fprintf(fp, "%s%-.*s", sep ?: " ", header_width, dots);
- /* preserve max indent depth for dots under sort headers */
- print_hierarchy_indent(sep, nr_sort, dots, fp);
-
fprintf(fp, "\n#\n");
return 2;
@@ -628,6 +638,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
bool first = true;
size_t linesz;
char *line = NULL;
+ unsigned indent;
init_rem_hits();
@@ -704,6 +715,8 @@ print_entries:
goto out;
}
+ indent = hists__overhead_width(hists) + 4;
+
for (nd = rb_first(&hists->entries); nd; nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
float percent;
@@ -720,6 +733,20 @@ print_entries:
if (max_rows && ++nr_rows >= max_rows)
break;
+ /*
+ * If all children are filtered out or percent-limited,
+ * display "no entry >= x.xx%" message.
+ */
+ if (!h->leaf && !hist_entry__has_hierarchy_children(h, min_pcnt)) {
+ int nr_sort = hists->nr_sort_keys;
+
+ print_hierarchy_indent(sep, nr_sort + h->depth + 1, spaces, fp);
+ fprintf(fp, "%*sno entry >= %.2f%%\n", indent, "", min_pcnt);
+
+ if (max_rows && ++nr_rows >= max_rows)
+ break;
+ }
+
if (h->ms.map == NULL && verbose > 1) {
__map_groups__fprintf_maps(h->thread->mg,
MAP__FUNCTION, fp);
diff --git a/tools/perf/util/color.c b/tools/perf/util/color.c
index e5fb88bab9e1..43e84aa27e4a 100644
--- a/tools/perf/util/color.c
+++ b/tools/perf/util/color.c
@@ -32,14 +32,15 @@ int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty)
return 0;
}
-int perf_color_default_config(const char *var, const char *value, void *cb)
+int perf_color_default_config(const char *var, const char *value,
+ void *cb __maybe_unused)
{
if (!strcmp(var, "color.ui")) {
perf_use_color_default = perf_config_colorbool(var, value, -1);
return 0;
}
- return perf_default_config(var, value, cb);
+ return 0;
}
static int __color_vsnprintf(char *bf, size_t size, const char *color,
diff --git a/tools/perf/util/data-convert-bt.c b/tools/perf/util/data-convert-bt.c
index b722e57d5a87..6729f4d9df7c 100644
--- a/tools/perf/util/data-convert-bt.c
+++ b/tools/perf/util/data-convert-bt.c
@@ -1117,7 +1117,7 @@ static int convert__config(const char *var, const char *value, void *cb)
return 0;
}
- return perf_default_config(var, value, cb);
+ return 0;
}
int bt_convert__perf2ctf(const char *input, const char *path, bool force)
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index c42e1967e970..86a03836a83f 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -1223,6 +1223,9 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
int err = 0;
evlist__for_each(evlist, evsel) {
+ if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
+ continue;
+
err = perf_evsel__set_filter(evsel, filter);
if (err)
break;
diff --git a/tools/perf/util/help-unknown-cmd.c b/tools/perf/util/help-unknown-cmd.c
index dc1e41c9b054..43a98a4dc1e1 100644
--- a/tools/perf/util/help-unknown-cmd.c
+++ b/tools/perf/util/help-unknown-cmd.c
@@ -6,7 +6,8 @@
static int autocorrect;
static struct cmdnames aliases;
-static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
+static int perf_unknown_cmd_config(const char *var, const char *value,
+ void *cb __maybe_unused)
{
if (!strcmp(var, "help.autocorrect"))
autocorrect = perf_config_int(var,value);
@@ -14,7 +15,7 @@ static int perf_unknown_cmd_config(const char *var, const char *value, void *cb)
if (!prefixcmp(var, "alias."))
add_cmdname(&aliases, var + 6, strlen(var + 6));
- return perf_default_config(var, value, cb);
+ return 0;
}
static int levenshtein_compare(const void *p1, const void *p2)
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 1c530428e087..4b8b67bc0cd8 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -1002,6 +1002,10 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
int64_t cmp = 0;
hists__for_each_sort_list(hists, fmt) {
+ if (perf_hpp__is_dynamic_entry(fmt) &&
+ !perf_hpp__defined_dynamic_entry(fmt, hists))
+ continue;
+
cmp = fmt->cmp(fmt, left, right);
if (cmp)
break;
@@ -1018,6 +1022,10 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
int64_t cmp = 0;
hists__for_each_sort_list(hists, fmt) {
+ if (perf_hpp__is_dynamic_entry(fmt) &&
+ !perf_hpp__defined_dynamic_entry(fmt, hists))
+ continue;
+
cmp = fmt->collapse(fmt, left, right);
if (cmp)
break;
@@ -1117,7 +1125,7 @@ static struct hist_entry *hierarchy_insert_entry(struct hists *hists,
new->fmt = fmt;
/* some fields are now passed to 'new' */
- if (perf_hpp__is_trace_entry(fmt))
+ if (perf_hpp__is_trace_entry(fmt) || perf_hpp__is_dynamic_entry(fmt))
he->trace_output = NULL;
else
new->trace_output = NULL;
@@ -1363,6 +1371,10 @@ static void hierarchy_insert_output_entry(struct rb_root *root,
rb_link_node(&he->rb_node, parent, p);
rb_insert_color(&he->rb_node, root);
+
+ /* update column width of dynamic entry */
+ if (perf_hpp__is_dynamic_entry(he->fmt))
+ he->fmt->sort(he->fmt, he, NULL);
}
static void hists__hierarchy_output_resort(struct hists *hists,
@@ -1432,6 +1444,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
struct rb_node **p = &entries->rb_node;
struct rb_node *parent = NULL;
struct hist_entry *iter;
+ struct perf_hpp_fmt *fmt;
if (use_callchain) {
if (callchain_param.mode == CHAIN_GRAPH_REL) {
@@ -1458,6 +1471,12 @@ static void __hists__insert_output_entry(struct rb_root *entries,
rb_link_node(&he->rb_node, parent, p);
rb_insert_color(&he->rb_node, entries);
+
+ perf_hpp_list__for_each_sort_list(&perf_hpp_list, fmt) {
+ if (perf_hpp__is_dynamic_entry(fmt) &&
+ perf_hpp__defined_dynamic_entry(fmt, he->hists))
+ fmt->sort(fmt, he, NULL); /* update column width */
+ }
}
static void output_resort(struct hists *hists, struct ui_progress *prog,
@@ -1582,6 +1601,31 @@ struct rb_node *rb_hierarchy_prev(struct rb_node *node)
return &he->rb_node;
}
+bool hist_entry__has_hierarchy_children(struct hist_entry *he, float limit)
+{
+ struct rb_node *node;
+ struct hist_entry *child;
+ float percent;
+
+ if (he->leaf)
+ return false;
+
+ node = rb_first(&he->hroot_out);
+ child = rb_entry(node, struct hist_entry, rb_node);
+
+ while (node && child->filtered) {
+ node = rb_next(node);
+ child = rb_entry(node, struct hist_entry, rb_node);
+ }
+
+ if (node)
+ percent = hist_entry__get_percent_limit(child);
+ else
+ percent = 0;
+
+ return node && percent >= limit;
+}
+
static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
enum hist_filter filter)
{
@@ -1600,6 +1644,7 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
/* force fold unfiltered entry for simplicity */
parent->unfolded = false;
+ parent->has_no_entry = false;
parent->row_offset = 0;
parent->nr_rows = 0;
next:
@@ -1612,6 +1657,7 @@ next:
/* force fold unfiltered entry for simplicity */
h->unfolded = false;
+ h->has_no_entry = false;
h->row_offset = 0;
h->nr_rows = 0;
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 722aa447f705..da5e50586bfd 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -78,6 +78,7 @@ struct hists {
u16 col_len[HISTC_NR_COLS];
int socket_filter;
struct perf_hpp_list *hpp_list;
+ int nr_sort_keys;
};
struct hist_entry_iter;
@@ -410,6 +411,7 @@ static inline int script_browse(const char *script_opt __maybe_unused)
#endif
unsigned int hists__sort_list_width(struct hists *hists);
+unsigned int hists__overhead_width(struct hists *hists);
void hist__account_cycles(struct branch_stack *bs, struct addr_location *al,
struct perf_sample *sample, bool nonany_branch_mode);
@@ -439,4 +441,6 @@ static inline struct rb_node *rb_hierarchy_next(struct rb_node *node)
#define HIERARCHY_INDENT 3
+bool hist_entry__has_hierarchy_children(struct hist_entry *he, float limit);
+
#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/parse-events.y b/tools/perf/util/parse-events.y
index d1fbcabbe70d..85c44ba79cad 100644
--- a/tools/perf/util/parse-events.y
+++ b/tools/perf/util/parse-events.y
@@ -217,14 +217,14 @@ event_def: event_pmu |
event_bpf_file
event_pmu:
-PE_NAME '/' event_config '/'
+PE_NAME opt_event_config
{
struct parse_events_evlist *data = _data;
struct list_head *list;
ALLOC_LIST(list);
- ABORT_ON(parse_events_add_pmu(data, list, $1, $3));
- parse_events_terms__delete($3);
+ ABORT_ON(parse_events_add_pmu(data, list, $1, $2));
+ parse_events_terms__delete($2);
$$ = list;
}
|
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 544509c159ce..b3aabc0d4eb0 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -187,6 +187,9 @@ static void define_event_symbols(struct event_format *event,
const char *ev_name,
struct print_arg *args)
{
+ if (args == NULL)
+ return;
+
switch (args->type) {
case PRINT_NULL:
break;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index d72fafc1c800..309d90fa7698 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -205,6 +205,9 @@ static void define_event_symbols(struct event_format *event,
const char *ev_name,
struct print_arg *args)
{
+ if (args == NULL)
+ return;
+
switch (args->type) {
case PRINT_NULL:
break;
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 6bee8bdfb91b..5888bfe9a193 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1764,6 +1764,9 @@ static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
if (hde->raw_trace)
goto raw_field;
+ if (!he->trace_output)
+ he->trace_output = get_trace_output(he);
+
field = hde->field;
namelen = strlen(field->name);
str = he->trace_output;
@@ -1813,6 +1816,11 @@ static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
+ if (b == NULL) {
+ update_dynamic_len(hde, a);
+ return 0;
+ }
+
field = hde->field;
if (field->flags & FIELD_IS_DYNAMIC) {
unsigned long long dyn;
@@ -1827,9 +1835,6 @@ static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
} else {
offset = field->offset;
size = field->size;
-
- update_dynamic_len(hde, a);
- update_dynamic_len(hde, b);
}
return memcmp(a->raw_data + offset, b->raw_data + offset, size);
@@ -2633,6 +2638,9 @@ out:
int setup_sorting(struct perf_evlist *evlist)
{
int err;
+ struct hists *hists;
+ struct perf_evsel *evsel;
+ struct perf_hpp_fmt *fmt;
err = __setup_sorting(evlist);
if (err < 0)
@@ -2644,6 +2652,22 @@ int setup_sorting(struct perf_evlist *evlist)
return err;
}
+ evlist__for_each(evlist, evsel) {
+ hists = evsel__hists(evsel);
+ hists->nr_sort_keys = perf_hpp_list.nr_sort_keys;
+
+ /*
+ * If dynamic entries were used, it might add multiple
+ * entries to each evsel for a single field name. Set
+ * actual number of sort keys for each hists.
+ */
+ perf_hpp_list__for_each_sort_list(&perf_hpp_list, fmt) {
+ if (perf_hpp__is_dynamic_entry(fmt) &&
+ !perf_hpp__defined_dynamic_entry(fmt, hists))
+ hists->nr_sort_keys--;
+ }
+ }
+
reset_dimensions();
/*
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index a8d53ffe0916..25a5529a94e4 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -117,6 +117,7 @@ struct hist_entry {
bool init_have_children;
bool unfolded;
bool has_children;
+ bool has_no_entry;
};
};
char *srcline;