perf/core improvements and fixes:
User visible: - Show extra line telling no entries below --percent-limit are at that --hierarchy level (Namhyung Kim) - 'perf report/top --hierarchy' assorted alignment fixes (Namhyung Kim) - Handle empty print fmts in 'perf script -s' i.e. when running python or perl scripts (Taeung Song) - Improve support for bpf-output events in 'perf trace' (Wang Nan) - Fix parsing of pmu events with empty list of modifiers, this cures a perf/core-only regression where '-e intel_pt//' got broken (Arnaldo Carvalho de Melo) Infrastructure: - Improve missing OpenJDK devel files error message in jvmti Makefile (Stephane Eranian) - Remove duplicated code and needless script_spec__findnew() (Taeung Song) - Bring perf_default_config to the very beginning at main(), removing the need for each subcommand to do this (Wang Nan) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJW0NtjAAoJENZQFvNTUqpA6VIQAJs4PKyXGm3NcqUNHhml/beN xLBz1o6JKxg72sKRHIm8IimPUIXm3ysqxQWQjKniXKqrznpAYlT180c+gUvJUghj ZbsHO8cNgaDjNOUMRhxiZTrQ4kJNdE9TmvPkoWwbAFgAxT1+CMHpjgwydWb0JLIv 0c7AxqKSg1FVTQSKDW67AYbWcp9IqoBoYpefLQNUKy2QJ/cqJtGcZXCaH9gKv5Vl mtiw+6bX7BCb+pLvZPcZ/69xvLrvhswGxBetjMS6ddTh63arvVvw4IzPW9XCI0gz MLSLAj8G0sG+mFFidl1/Mka03qy7+XKndhKEDhrKdEcf7T0FnHuArdWOLXfeHIa9 GpTEl6MTR2SSvp8zvwLDxCFZKgBPkvPrS014VL2kExc/sdcAW7Dpz+GGxHM7K+Rn QsgBMmMwtsodOzdqjfH9YJTIhc73gDdytucrzfsO9S9iUkwK+UbahPEJmmU9Y0WY 6Pb/JAcznt7j1AnRIlBq5n8M758CxRqy7aHIDOST5rF/rSPFWLBF+41NodhybcKL 9uOq9n+e8qbXlQxithvom6H3aA+Aw1siu2q1/gTIAXBwg3VIWQeqQWFIGPPaBW3u JLb8lEMTFBJILTAWWy8W/nNwfYi31aI1EP4eRm9hcOZTGj8O3TxzCiZFYHohvE/O QAkPbInvsLDds2BeDtWp =tvYO -----END PGP SIGNATURE----- Merge tag 'perf-core-for-mingo-20160226' of git://git.kernel.org/pub/scm/linux/kernel/git/acme/linux into perf/core Pull perf/core improvements and fixes from Arnaldo Carvalho de Melo: User visible changes: - Show extra line telling no entries below --percent-limit are at that --hierarchy level (Namhyung Kim) - 'perf report/top --hierarchy' assorted alignment fixes (Namhyung Kim) - Handle empty print fmts in 'perf script -s' i.e. when running python or perl scripts (Taeung Song) - Improve support for bpf-output events in 'perf trace' (Wang Nan) - Fix parsing of pmu events with empty list of modifiers, this cures a perf/core-only regression where '-e intel_pt//' got broken (Arnaldo Carvalho de Melo) Infrastructure changes: - Improve missing OpenJDK devel files error message in jvmti Makefile (Stephane Eranian) - Remove duplicated code and needless script_spec__findnew() (Taeung Song) - Bring perf_default_config to the very beginning at main(), removing the need for each subcommand to do this (Wang Nan) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
ce1984cc45
@ -1264,8 +1264,6 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
perf_config(perf_default_config, NULL);
|
|
||||||
|
|
||||||
argc = parse_options(argc, argv, options, diff_usage, 0);
|
argc = parse_options(argc, argv, options, diff_usage, 0);
|
||||||
|
|
||||||
if (symbol__init(NULL) < 0)
|
if (symbol__init(NULL) < 0)
|
||||||
|
@ -272,7 +272,7 @@ static int perf_help_config(const char *var, const char *value, void *cb)
|
|||||||
if (!prefixcmp(var, "man."))
|
if (!prefixcmp(var, "man."))
|
||||||
return add_man_viewer_info(var, value);
|
return add_man_viewer_info(var, value);
|
||||||
|
|
||||||
return perf_default_config(var, value, cb);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct cmdnames main_cmds, other_cmds;
|
static struct cmdnames main_cmds, other_cmds;
|
||||||
|
@ -1834,7 +1834,7 @@ static int __cmd_record(int argc, const char **argv)
|
|||||||
return cmd_record(i, rec_argv, NULL);
|
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(var, "kmem.default")) {
|
||||||
if (!strcmp(value, "slab"))
|
if (!strcmp(value, "slab"))
|
||||||
@ -1847,7 +1847,7 @@ static int kmem_config(const char *var, const char *value, void *cb)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return perf_default_config(var, value, cb);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
|
int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
|
||||||
|
@ -90,7 +90,7 @@ static int report__config(const char *var, const char *value, void *cb)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return perf_default_config(var, value, cb);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hist_iter__report_callback(struct hist_entry_iter *iter,
|
static int hist_iter__report_callback(struct hist_entry_iter *iter,
|
||||||
|
@ -1212,23 +1212,6 @@ static struct script_spec *script_spec__find(const char *spec)
|
|||||||
return NULL;
|
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)
|
int script_spec_register(const char *spec, struct scripting_ops *ops)
|
||||||
{
|
{
|
||||||
struct script_spec *s;
|
struct script_spec *s;
|
||||||
@ -1237,9 +1220,11 @@ int script_spec_register(const char *spec, struct scripting_ops *ops)
|
|||||||
if (s)
|
if (s)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
s = script_spec__findnew(spec, ops);
|
s = script_spec__new(spec, ops);
|
||||||
if (!s)
|
if (!s)
|
||||||
return -1;
|
return -1;
|
||||||
|
else
|
||||||
|
script_spec__add(s);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1065,7 +1065,7 @@ parse_callchain_opt(const struct option *opt, const char *arg, int unset)
|
|||||||
return parse_callchain_top_opt(arg);
|
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"))
|
if (!strcmp(var, "top.call-graph"))
|
||||||
var = "call-graph.record-mode"; /* fall-through */
|
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 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return perf_default_config(var, value, cb);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -33,6 +33,7 @@
|
|||||||
#include "util/stat.h"
|
#include "util/stat.h"
|
||||||
#include "trace-event.h"
|
#include "trace-event.h"
|
||||||
#include "util/parse-events.h"
|
#include "util/parse-events.h"
|
||||||
|
#include "util/bpf-loader.h"
|
||||||
|
|
||||||
#include <libaudit.h>
|
#include <libaudit.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -2177,6 +2178,37 @@ out_dump:
|
|||||||
return 0;
|
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,
|
static int trace__event_handler(struct trace *trace, struct perf_evsel *evsel,
|
||||||
union perf_event *event __maybe_unused,
|
union perf_event *event __maybe_unused,
|
||||||
struct perf_sample *sample)
|
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);
|
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,
|
event_format__fprintf(evsel->tp_format, sample->cpu,
|
||||||
sample->raw_data, sample->raw_size,
|
sample->raw_data, sample->raw_size,
|
||||||
trace->output);
|
trace->output);
|
||||||
@ -2586,6 +2620,16 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
|
|||||||
if (err < 0)
|
if (err < 0)
|
||||||
goto out_error_open;
|
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
|
* 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
|
* case where no threads were specified in the command line, but a
|
||||||
|
@ -35,12 +35,21 @@ SOLIBEXT=so
|
|||||||
|
|
||||||
# The following works at least on fedora 23, you may need the next
|
# The following works at least on fedora 23, you may need the next
|
||||||
# line for other distros.
|
# line for other distros.
|
||||||
ifeq (,$(wildcard /usr/sbin/update-java-alternatives))
|
ifneq (,$(wildcard /usr/sbin/update-java-alternatives))
|
||||||
JDIR=$(shell alternatives --display java | tail -1 | cut -d' ' -f 5 | sed 's%/jre/bin/java.%%g')
|
|
||||||
else
|
|
||||||
JDIR=$(shell /usr/sbin/update-java-alternatives -l | head -1 | cut -d ' ' -f 3)
|
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
|
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()
|
# -lrt required in 32-bit mode for clock_gettime()
|
||||||
LIBS=-lelf -lrt
|
LIBS=-lelf -lrt
|
||||||
INCDIR=-I $(JDIR)/include -I $(JDIR)/include/linux
|
INCDIR=-I $(JDIR)/include -I $(JDIR)/include/linux
|
||||||
|
@ -454,11 +454,12 @@ static void handle_internal_command(int argc, const char **argv)
|
|||||||
|
|
||||||
static void execv_dashed_external(const char **argv)
|
static void execv_dashed_external(const char **argv)
|
||||||
{
|
{
|
||||||
struct strbuf cmd = STRBUF_INIT;
|
char *cmd;
|
||||||
const char *tmp;
|
const char *tmp;
|
||||||
int status;
|
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
|
* 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.
|
* restore it on error.
|
||||||
*/
|
*/
|
||||||
tmp = argv[0];
|
tmp = argv[0];
|
||||||
argv[0] = cmd.buf;
|
argv[0] = cmd;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we fail because the command is not found, it is
|
* 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);
|
status = run_command_v_opt(argv, 0);
|
||||||
if (status != -ERR_RUN_COMMAND_EXEC) {
|
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]);
|
die("unable to run '%s'", argv[0]);
|
||||||
|
}
|
||||||
exit(-status);
|
exit(-status);
|
||||||
}
|
}
|
||||||
errno = ENOENT; /* as if we called execvp */
|
errno = ENOENT; /* as if we called execvp */
|
||||||
|
|
||||||
argv[0] = tmp;
|
argv[0] = tmp;
|
||||||
|
zfree(&cmd);
|
||||||
strbuf_release(&cmd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int run_argv(int *argcp, const char ***argv)
|
static int run_argv(int *argcp, const char ***argv)
|
||||||
@ -546,6 +548,8 @@ int main(int argc, const char **argv)
|
|||||||
|
|
||||||
srandom(time(NULL));
|
srandom(time(NULL));
|
||||||
|
|
||||||
|
perf_config(perf_default_config, NULL);
|
||||||
|
|
||||||
/* get debugfs/tracefs mount point from /proc/mounts */
|
/* get debugfs/tracefs mount point from /proc/mounts */
|
||||||
tracing_path_mount();
|
tracing_path_mount();
|
||||||
|
|
||||||
|
@ -6,12 +6,6 @@
|
|||||||
#include "tests.h"
|
#include "tests.h"
|
||||||
#include "debug.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
|
#ifdef HAVE_LIBBPF_SUPPORT
|
||||||
static int test__bpf_parsing(void *obj_buf, size_t obj_buf_sz)
|
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)
|
if (should_load_fail)
|
||||||
*should_load_fail = bpf_source_table[idx].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
|
* 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
|
* and clang is not found in $PATH, and this is not perf test -v
|
||||||
|
@ -260,6 +260,9 @@ static int hierarchy_count_rows(struct hist_browser *hb, struct hist_entry *he,
|
|||||||
if (he->leaf)
|
if (he->leaf)
|
||||||
return callchain__count_rows(&he->sorted_chain);
|
return callchain__count_rows(&he->sorted_chain);
|
||||||
|
|
||||||
|
if (he->has_no_entry)
|
||||||
|
return 1;
|
||||||
|
|
||||||
node = rb_first(&he->hroot_out);
|
node = rb_first(&he->hroot_out);
|
||||||
while (node) {
|
while (node) {
|
||||||
float percent;
|
float percent;
|
||||||
@ -409,10 +412,18 @@ static bool hist_browser__toggle_fold(struct hist_browser *browser)
|
|||||||
/* account grand children */
|
/* account grand children */
|
||||||
if (symbol_conf.report_hierarchy)
|
if (symbol_conf.report_hierarchy)
|
||||||
browser->b.nr_entries += child_rows - he->nr_rows;
|
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 {
|
} else {
|
||||||
if (symbol_conf.report_hierarchy)
|
if (symbol_conf.report_hierarchy)
|
||||||
browser->b.nr_entries -= child_rows - he->nr_rows;
|
browser->b.nr_entries -= child_rows - he->nr_rows;
|
||||||
|
|
||||||
|
if (he->has_no_entry)
|
||||||
|
he->has_no_entry = false;
|
||||||
|
|
||||||
he->nr_rows = 0;
|
he->nr_rows = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -545,6 +556,12 @@ __hist_browser__set_folding(struct hist_browser *browser, bool unfold)
|
|||||||
browser->nr_hierarchy_entries++;
|
browser->nr_hierarchy_entries++;
|
||||||
if (he->leaf)
|
if (he->leaf)
|
||||||
browser->nr_callchain_rows += he->nr_rows;
|
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) {
|
if (fmt->color) {
|
||||||
width -= fmt->color(fmt, &hpp, entry);
|
width -= fmt->color(fmt, &hpp, entry);
|
||||||
} else {
|
} else {
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
width -= fmt->entry(fmt, &hpp, entry);
|
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;
|
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)
|
static int advance_hpp_check(struct perf_hpp *hpp, int inc)
|
||||||
{
|
{
|
||||||
advance_hpp(hpp, 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;
|
struct perf_hpp_fmt *fmt;
|
||||||
size_t ret = 0;
|
size_t ret = 0;
|
||||||
int column = 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;
|
bool first = true;
|
||||||
|
|
||||||
ret = scnprintf(buf, size, " ");
|
ret = scnprintf(buf, size, " ");
|
||||||
@ -1490,6 +1581,8 @@ static int hists_browser__scnprintf_hierarchy_headers(struct hist_browser *brows
|
|||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
hists__for_each_format(hists, fmt) {
|
hists__for_each_format(hists, fmt) {
|
||||||
|
char *start;
|
||||||
|
|
||||||
if (!perf_hpp__is_sort_entry(fmt) && !perf_hpp__is_dynamic_entry(fmt))
|
if (!perf_hpp__is_sort_entry(fmt) && !perf_hpp__is_dynamic_entry(fmt))
|
||||||
continue;
|
continue;
|
||||||
if (perf_hpp__should_skip(fmt, hists))
|
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';
|
dummy_hpp.buf[ret] = '\0';
|
||||||
rtrim(dummy_hpp.buf);
|
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))
|
if (advance_hpp_check(&dummy_hpp, ret))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1546,7 +1644,7 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
|
|||||||
u16 header_offset = 0;
|
u16 header_offset = 0;
|
||||||
struct rb_node *nd;
|
struct rb_node *nd;
|
||||||
struct hist_browser *hb = container_of(browser, struct hist_browser, b);
|
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) {
|
if (hb->show_headers) {
|
||||||
hist_browser__show_headers(hb);
|
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,
|
row += hist_browser__show_hierarchy_entry(hb, h, row,
|
||||||
h->depth,
|
h->depth,
|
||||||
nr_sort);
|
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 {
|
} else {
|
||||||
row += hist_browser__show_entry(hb, h, row);
|
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),
|
struct rb_node *nd = hists__filter_entries(rb_first(browser->b.entries),
|
||||||
browser->min_pcnt);
|
browser->min_pcnt);
|
||||||
int printed = 0;
|
int printed = 0;
|
||||||
int nr_sort = browser->hists->hpp_list->nr_sort_keys;
|
int nr_sort = browser->hists->nr_sort_keys;
|
||||||
|
|
||||||
while (nd) {
|
while (nd) {
|
||||||
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
|
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) {
|
while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
|
||||||
he = rb_entry(nd, struct hist_entry, rb_node);
|
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)
|
if (!he->leaf || !symbol_conf.use_callchain)
|
||||||
goto next;
|
goto next;
|
||||||
|
|
||||||
@ -2477,12 +2588,7 @@ static void hist_browser__update_percent_limit(struct hist_browser *hb,
|
|||||||
min_callchain_hits, &callchain_param);
|
min_callchain_hits, &callchain_param);
|
||||||
|
|
||||||
next:
|
next:
|
||||||
/*
|
nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD);
|
||||||
* 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);
|
|
||||||
|
|
||||||
/* force to re-evaluate folding state of callchains */
|
/* force to re-evaluate folding state of callchains */
|
||||||
he->init_have_children = false;
|
he->init_have_children = false;
|
||||||
|
@ -449,6 +449,17 @@ static void perf_gtk__add_hierarchy_entries(struct hists *hists,
|
|||||||
perf_gtk__add_hierarchy_entries(hists, &he->hroot_out,
|
perf_gtk__add_hierarchy_entries(hists, &he->hroot_out,
|
||||||
store, &iter, hpp,
|
store, &iter, hpp,
|
||||||
min_pcnt);
|
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) {
|
if (symbol_conf.use_callchain && he->leaf) {
|
||||||
|
@ -643,6 +643,28 @@ unsigned int hists__sort_list_width(struct hists *hists)
|
|||||||
return ret;
|
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)
|
void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
|
||||||
{
|
{
|
||||||
if (perf_hpp__is_sort_entry(fmt))
|
if (perf_hpp__is_sort_entry(fmt))
|
||||||
|
@ -418,6 +418,7 @@ static int hist_entry__hierarchy_fprintf(struct hist_entry *he,
|
|||||||
const char *sep = symbol_conf.field_sep;
|
const char *sep = symbol_conf.field_sep;
|
||||||
struct perf_hpp_fmt *fmt;
|
struct perf_hpp_fmt *fmt;
|
||||||
char *buf = hpp->buf;
|
char *buf = hpp->buf;
|
||||||
|
size_t size = hpp->size;
|
||||||
int ret, printed = 0;
|
int ret, printed = 0;
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
||||||
@ -457,6 +458,11 @@ static int hist_entry__hierarchy_fprintf(struct hist_entry *he,
|
|||||||
(nr_sort_key - 1) * HIERARCHY_INDENT + 2, "");
|
(nr_sort_key - 1) * HIERARCHY_INDENT + 2, "");
|
||||||
advance_hpp(hpp, ret);
|
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
|
* No need to call hist_entry__snprintf_alignment() since this
|
||||||
* fmt is always the last column in the hierarchy mode.
|
* 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
|
else
|
||||||
fmt->entry(fmt, hpp, he);
|
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) {
|
if (symbol_conf.use_callchain && he->leaf) {
|
||||||
u64 total = hists__total_period(hists);
|
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;
|
size = hpp.size = bfsz;
|
||||||
|
|
||||||
if (symbol_conf.report_hierarchy) {
|
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,
|
return hist_entry__hierarchy_fprintf(he, &hpp, nr_sort,
|
||||||
hists, fp);
|
hists, fp);
|
||||||
@ -525,11 +535,12 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
|
|||||||
{
|
{
|
||||||
bool first = true;
|
bool first = true;
|
||||||
int nr_sort;
|
int nr_sort;
|
||||||
|
int depth;
|
||||||
unsigned width = 0;
|
unsigned width = 0;
|
||||||
unsigned header_width = 0;
|
unsigned header_width = 0;
|
||||||
struct perf_hpp_fmt *fmt;
|
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 */
|
/* preserve max indent depth for column headers */
|
||||||
print_hierarchy_indent(sep, nr_sort, spaces, fp);
|
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)
|
if (!first)
|
||||||
header_width += fprintf(fp, " / ");
|
header_width += fprintf(fp, " / ");
|
||||||
else {
|
else {
|
||||||
header_width += fprintf(fp, "%s", sep ?: " ");
|
fprintf(fp, "%s", sep ?: " ");
|
||||||
first = false;
|
first = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt->header(fmt, hpp, hists_to_evsel(hists));
|
fmt->header(fmt, hpp, hists_to_evsel(hists));
|
||||||
rtrim(hpp->buf);
|
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# ");
|
fprintf(fp, "\n# ");
|
||||||
|
|
||||||
/* preserve max indent depth for initial dots */
|
/* 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);
|
fprintf(fp, "%.*s", width, dots);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
depth = 0;
|
||||||
hists__for_each_format(hists, fmt) {
|
hists__for_each_format(hists, fmt) {
|
||||||
if (!perf_hpp__is_sort_entry(fmt) && !perf_hpp__is_dynamic_entry(fmt))
|
if (!perf_hpp__is_sort_entry(fmt) && !perf_hpp__is_dynamic_entry(fmt))
|
||||||
continue;
|
continue;
|
||||||
@ -597,15 +606,16 @@ static int print_hierarchy_header(struct hists *hists, struct perf_hpp *hpp,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
width = fmt->width(fmt, hpp, hists_to_evsel(hists));
|
width = fmt->width(fmt, hpp, hists_to_evsel(hists));
|
||||||
|
width += depth * HIERARCHY_INDENT;
|
||||||
|
|
||||||
if (width > header_width)
|
if (width > header_width)
|
||||||
header_width = width;
|
header_width = width;
|
||||||
|
|
||||||
|
depth++;
|
||||||
}
|
}
|
||||||
|
|
||||||
fprintf(fp, "%s%-.*s", sep ?: " ", header_width, dots);
|
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");
|
fprintf(fp, "\n#\n");
|
||||||
|
|
||||||
return 2;
|
return 2;
|
||||||
@ -628,6 +638,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
|
|||||||
bool first = true;
|
bool first = true;
|
||||||
size_t linesz;
|
size_t linesz;
|
||||||
char *line = NULL;
|
char *line = NULL;
|
||||||
|
unsigned indent;
|
||||||
|
|
||||||
init_rem_hits();
|
init_rem_hits();
|
||||||
|
|
||||||
@ -704,6 +715,8 @@ print_entries:
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
indent = hists__overhead_width(hists) + 4;
|
||||||
|
|
||||||
for (nd = rb_first(&hists->entries); nd; nd = __rb_hierarchy_next(nd, HMD_FORCE_CHILD)) {
|
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);
|
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
|
||||||
float percent;
|
float percent;
|
||||||
@ -720,6 +733,20 @@ print_entries:
|
|||||||
if (max_rows && ++nr_rows >= max_rows)
|
if (max_rows && ++nr_rows >= max_rows)
|
||||||
break;
|
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) {
|
if (h->ms.map == NULL && verbose > 1) {
|
||||||
__map_groups__fprintf_maps(h->thread->mg,
|
__map_groups__fprintf_maps(h->thread->mg,
|
||||||
MAP__FUNCTION, fp);
|
MAP__FUNCTION, fp);
|
||||||
|
@ -32,14 +32,15 @@ int perf_config_colorbool(const char *var, const char *value, int stdout_is_tty)
|
|||||||
return 0;
|
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")) {
|
if (!strcmp(var, "color.ui")) {
|
||||||
perf_use_color_default = perf_config_colorbool(var, value, -1);
|
perf_use_color_default = perf_config_colorbool(var, value, -1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return perf_default_config(var, value, cb);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __color_vsnprintf(char *bf, size_t size, const char *color,
|
static int __color_vsnprintf(char *bf, size_t size, const char *color,
|
||||||
|
@ -1117,7 +1117,7 @@ static int convert__config(const char *var, const char *value, void *cb)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return perf_default_config(var, value, cb);
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bt_convert__perf2ctf(const char *input, const char *path, bool force)
|
int bt_convert__perf2ctf(const char *input, const char *path, bool force)
|
||||||
|
@ -1223,6 +1223,9 @@ int perf_evlist__set_filter(struct perf_evlist *evlist, const char *filter)
|
|||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
evlist__for_each(evlist, evsel) {
|
evlist__for_each(evlist, evsel) {
|
||||||
|
if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
|
||||||
|
continue;
|
||||||
|
|
||||||
err = perf_evsel__set_filter(evsel, filter);
|
err = perf_evsel__set_filter(evsel, filter);
|
||||||
if (err)
|
if (err)
|
||||||
break;
|
break;
|
||||||
|
@ -6,7 +6,8 @@
|
|||||||
static int autocorrect;
|
static int autocorrect;
|
||||||
static struct cmdnames aliases;
|
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"))
|
if (!strcmp(var, "help.autocorrect"))
|
||||||
autocorrect = perf_config_int(var,value);
|
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."))
|
if (!prefixcmp(var, "alias."))
|
||||||
add_cmdname(&aliases, var + 6, strlen(var + 6));
|
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)
|
static int levenshtein_compare(const void *p1, const void *p2)
|
||||||
|
@ -1002,6 +1002,10 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
|
|||||||
int64_t cmp = 0;
|
int64_t cmp = 0;
|
||||||
|
|
||||||
hists__for_each_sort_list(hists, fmt) {
|
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);
|
cmp = fmt->cmp(fmt, left, right);
|
||||||
if (cmp)
|
if (cmp)
|
||||||
break;
|
break;
|
||||||
@ -1018,6 +1022,10 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
|
|||||||
int64_t cmp = 0;
|
int64_t cmp = 0;
|
||||||
|
|
||||||
hists__for_each_sort_list(hists, fmt) {
|
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);
|
cmp = fmt->collapse(fmt, left, right);
|
||||||
if (cmp)
|
if (cmp)
|
||||||
break;
|
break;
|
||||||
@ -1117,7 +1125,7 @@ static struct hist_entry *hierarchy_insert_entry(struct hists *hists,
|
|||||||
new->fmt = fmt;
|
new->fmt = fmt;
|
||||||
|
|
||||||
/* some fields are now passed to 'new' */
|
/* 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;
|
he->trace_output = NULL;
|
||||||
else
|
else
|
||||||
new->trace_output = NULL;
|
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_link_node(&he->rb_node, parent, p);
|
||||||
rb_insert_color(&he->rb_node, root);
|
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,
|
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 **p = &entries->rb_node;
|
||||||
struct rb_node *parent = NULL;
|
struct rb_node *parent = NULL;
|
||||||
struct hist_entry *iter;
|
struct hist_entry *iter;
|
||||||
|
struct perf_hpp_fmt *fmt;
|
||||||
|
|
||||||
if (use_callchain) {
|
if (use_callchain) {
|
||||||
if (callchain_param.mode == CHAIN_GRAPH_REL) {
|
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_link_node(&he->rb_node, parent, p);
|
||||||
rb_insert_color(&he->rb_node, entries);
|
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,
|
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;
|
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,
|
static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
|
||||||
enum hist_filter filter)
|
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 */
|
/* force fold unfiltered entry for simplicity */
|
||||||
parent->unfolded = false;
|
parent->unfolded = false;
|
||||||
|
parent->has_no_entry = false;
|
||||||
parent->row_offset = 0;
|
parent->row_offset = 0;
|
||||||
parent->nr_rows = 0;
|
parent->nr_rows = 0;
|
||||||
next:
|
next:
|
||||||
@ -1612,6 +1657,7 @@ next:
|
|||||||
|
|
||||||
/* force fold unfiltered entry for simplicity */
|
/* force fold unfiltered entry for simplicity */
|
||||||
h->unfolded = false;
|
h->unfolded = false;
|
||||||
|
h->has_no_entry = false;
|
||||||
h->row_offset = 0;
|
h->row_offset = 0;
|
||||||
h->nr_rows = 0;
|
h->nr_rows = 0;
|
||||||
|
|
||||||
|
@ -78,6 +78,7 @@ struct hists {
|
|||||||
u16 col_len[HISTC_NR_COLS];
|
u16 col_len[HISTC_NR_COLS];
|
||||||
int socket_filter;
|
int socket_filter;
|
||||||
struct perf_hpp_list *hpp_list;
|
struct perf_hpp_list *hpp_list;
|
||||||
|
int nr_sort_keys;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hist_entry_iter;
|
struct hist_entry_iter;
|
||||||
@ -410,6 +411,7 @@ static inline int script_browse(const char *script_opt __maybe_unused)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
unsigned int hists__sort_list_width(struct hists *hists);
|
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,
|
void hist__account_cycles(struct branch_stack *bs, struct addr_location *al,
|
||||||
struct perf_sample *sample, bool nonany_branch_mode);
|
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
|
#define HIERARCHY_INDENT 3
|
||||||
|
|
||||||
|
bool hist_entry__has_hierarchy_children(struct hist_entry *he, float limit);
|
||||||
|
|
||||||
#endif /* __PERF_HIST_H */
|
#endif /* __PERF_HIST_H */
|
||||||
|
@ -217,14 +217,14 @@ event_def: event_pmu |
|
|||||||
event_bpf_file
|
event_bpf_file
|
||||||
|
|
||||||
event_pmu:
|
event_pmu:
|
||||||
PE_NAME '/' event_config '/'
|
PE_NAME opt_event_config
|
||||||
{
|
{
|
||||||
struct parse_events_evlist *data = _data;
|
struct parse_events_evlist *data = _data;
|
||||||
struct list_head *list;
|
struct list_head *list;
|
||||||
|
|
||||||
ALLOC_LIST(list);
|
ALLOC_LIST(list);
|
||||||
ABORT_ON(parse_events_add_pmu(data, list, $1, $3));
|
ABORT_ON(parse_events_add_pmu(data, list, $1, $2));
|
||||||
parse_events_terms__delete($3);
|
parse_events_terms__delete($2);
|
||||||
$$ = list;
|
$$ = list;
|
||||||
}
|
}
|
||||||
|
|
|
|
||||||
|
@ -187,6 +187,9 @@ static void define_event_symbols(struct event_format *event,
|
|||||||
const char *ev_name,
|
const char *ev_name,
|
||||||
struct print_arg *args)
|
struct print_arg *args)
|
||||||
{
|
{
|
||||||
|
if (args == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
switch (args->type) {
|
switch (args->type) {
|
||||||
case PRINT_NULL:
|
case PRINT_NULL:
|
||||||
break;
|
break;
|
||||||
|
@ -205,6 +205,9 @@ static void define_event_symbols(struct event_format *event,
|
|||||||
const char *ev_name,
|
const char *ev_name,
|
||||||
struct print_arg *args)
|
struct print_arg *args)
|
||||||
{
|
{
|
||||||
|
if (args == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
switch (args->type) {
|
switch (args->type) {
|
||||||
case PRINT_NULL:
|
case PRINT_NULL:
|
||||||
break;
|
break;
|
||||||
|
@ -1764,6 +1764,9 @@ static int __sort__hde_entry(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
|
|||||||
if (hde->raw_trace)
|
if (hde->raw_trace)
|
||||||
goto raw_field;
|
goto raw_field;
|
||||||
|
|
||||||
|
if (!he->trace_output)
|
||||||
|
he->trace_output = get_trace_output(he);
|
||||||
|
|
||||||
field = hde->field;
|
field = hde->field;
|
||||||
namelen = strlen(field->name);
|
namelen = strlen(field->name);
|
||||||
str = he->trace_output;
|
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);
|
hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
|
||||||
|
|
||||||
|
if (b == NULL) {
|
||||||
|
update_dynamic_len(hde, a);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
field = hde->field;
|
field = hde->field;
|
||||||
if (field->flags & FIELD_IS_DYNAMIC) {
|
if (field->flags & FIELD_IS_DYNAMIC) {
|
||||||
unsigned long long dyn;
|
unsigned long long dyn;
|
||||||
@ -1827,9 +1835,6 @@ static int64_t __sort__hde_cmp(struct perf_hpp_fmt *fmt,
|
|||||||
} else {
|
} else {
|
||||||
offset = field->offset;
|
offset = field->offset;
|
||||||
size = field->size;
|
size = field->size;
|
||||||
|
|
||||||
update_dynamic_len(hde, a);
|
|
||||||
update_dynamic_len(hde, b);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return memcmp(a->raw_data + offset, b->raw_data + offset, size);
|
return memcmp(a->raw_data + offset, b->raw_data + offset, size);
|
||||||
@ -2633,6 +2638,9 @@ out:
|
|||||||
int setup_sorting(struct perf_evlist *evlist)
|
int setup_sorting(struct perf_evlist *evlist)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
struct hists *hists;
|
||||||
|
struct perf_evsel *evsel;
|
||||||
|
struct perf_hpp_fmt *fmt;
|
||||||
|
|
||||||
err = __setup_sorting(evlist);
|
err = __setup_sorting(evlist);
|
||||||
if (err < 0)
|
if (err < 0)
|
||||||
@ -2644,6 +2652,22 @@ int setup_sorting(struct perf_evlist *evlist)
|
|||||||
return err;
|
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();
|
reset_dimensions();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -117,6 +117,7 @@ struct hist_entry {
|
|||||||
bool init_have_children;
|
bool init_have_children;
|
||||||
bool unfolded;
|
bool unfolded;
|
||||||
bool has_children;
|
bool has_children;
|
||||||
|
bool has_no_entry;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
char *srcline;
|
char *srcline;
|
||||||
|
Loading…
Reference in New Issue
Block a user