Commit e450f90e authored by Ingo Molnar's avatar Ingo Molnar

Merge tag 'perf-core-for-mingo' of...

Merge tag 'perf-core-for-mingo' of git://git.kernel.org/pub/scm/linux/kernel/git/jolsa/perf into perf/core

Pull perf/core improvements and fixes from Jiri Olsa:

  * Android related fixes for pager and map dso resolving (Michael Lentine)

  * Add -F option for specifying output fields (Namhyung Kim)
Signed-off-by: default avatarJiri Olsa <jolsa@kernel.org>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents 6480c561 eca81836
...@@ -50,7 +50,8 @@ OPTIONS ...@@ -50,7 +50,8 @@ OPTIONS
-s:: -s::
--sort=:: --sort=::
Sort by key(s): pid, comm, dso, symbol. Sort by key(s): pid, comm, dso, symbol, cpu, parent, srcline.
Please see description of --sort in the perf-report man page.
-t:: -t::
--field-separator=:: --field-separator=::
...@@ -202,4 +203,4 @@ If specified the 'Weighted diff' column is displayed with value 'd' computed as: ...@@ -202,4 +203,4 @@ If specified the 'Weighted diff' column is displayed with value 'd' computed as:
SEE ALSO SEE ALSO
-------- --------
linkperf:perf-record[1] linkperf:perf-record[1], linkperf:perf-report[1]
...@@ -79,6 +79,15 @@ OPTIONS ...@@ -79,6 +79,15 @@ OPTIONS
abort cost. This is the global weight. abort cost. This is the global weight.
- local_weight: Local weight version of the weight above. - local_weight: Local weight version of the weight above.
- transaction: Transaction abort flags. - transaction: Transaction abort flags.
- overhead: Overhead percentage of sample
- overhead_sys: Overhead percentage of sample running in system mode
- overhead_us: Overhead percentage of sample running in user mode
- overhead_guest_sys: Overhead percentage of sample running in system mode
on guest machine
- overhead_guest_us: Overhead percentage of sample running in user mode on
guest machine
- sample: Number of sample
- period: Raw number of event count of sample
By default, comm, dso and symbol keys are used. By default, comm, dso and symbol keys are used.
(i.e. --sort comm,dso,symbol) (i.e. --sort comm,dso,symbol)
...@@ -98,6 +107,16 @@ OPTIONS ...@@ -98,6 +107,16 @@ OPTIONS
And default sort keys are changed to comm, dso_from, symbol_from, dso_to And default sort keys are changed to comm, dso_from, symbol_from, dso_to
and symbol_to, see '--branch-stack'. and symbol_to, see '--branch-stack'.
-F::
--fields=::
Specify output field - multiple keys can be specified in CSV format.
Following fields are available:
overhead, overhead_sys, overhead_us, sample and period.
Also it can contain any sort key(s).
By default, every sort keys not specified in -F will be appended
automatically.
-p:: -p::
--parent=<regex>:: --parent=<regex>::
A regex filter to identify parent. The parent is a caller of this A regex filter to identify parent. The parent is a caller of this
......
...@@ -113,7 +113,17 @@ Default is to monitor all CPUS. ...@@ -113,7 +113,17 @@ Default is to monitor all CPUS.
-s:: -s::
--sort:: --sort::
Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight, Sort by key(s): pid, comm, dso, symbol, parent, srcline, weight,
local_weight, abort, in_tx, transaction local_weight, abort, in_tx, transaction, overhead, sample, period.
Please see description of --sort in the perf-report man page.
--fields=::
Specify output field - multiple keys can be specified in CSV format.
Following fields are available:
overhead, overhead_sys, overhead_us, sample and period.
Also it can contain any sort key(s).
By default, every sort keys not specified in --field will be appended
automatically.
-n:: -n::
--show-nr-samples:: --show-nr-samples::
...@@ -212,4 +222,4 @@ Pressing any unmapped key displays a menu, and prompts for input. ...@@ -212,4 +222,4 @@ Pressing any unmapped key displays a menu, and prompts for input.
SEE ALSO SEE ALSO
-------- --------
linkperf:perf-stat[1], linkperf:perf-list[1] linkperf:perf-stat[1], linkperf:perf-list[1], linkperf:perf-report[1]
...@@ -399,6 +399,7 @@ LIB_OBJS += $(OUTPUT)tests/pmu.o ...@@ -399,6 +399,7 @@ LIB_OBJS += $(OUTPUT)tests/pmu.o
LIB_OBJS += $(OUTPUT)tests/hists_common.o LIB_OBJS += $(OUTPUT)tests/hists_common.o
LIB_OBJS += $(OUTPUT)tests/hists_link.o LIB_OBJS += $(OUTPUT)tests/hists_link.o
LIB_OBJS += $(OUTPUT)tests/hists_filter.o LIB_OBJS += $(OUTPUT)tests/hists_filter.o
LIB_OBJS += $(OUTPUT)tests/hists_output.o
LIB_OBJS += $(OUTPUT)tests/python-use.o LIB_OBJS += $(OUTPUT)tests/python-use.o
LIB_OBJS += $(OUTPUT)tests/bp_signal.o LIB_OBJS += $(OUTPUT)tests/bp_signal.o
LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o LIB_OBJS += $(OUTPUT)tests/bp_signal_overflow.o
......
...@@ -60,7 +60,6 @@ static int data__files_cnt; ...@@ -60,7 +60,6 @@ static int data__files_cnt;
#define data__for_each_file(i, d) data__for_each_file_start(i, d, 0) #define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
#define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1) #define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
static char diff__default_sort_order[] = "dso,symbol";
static bool force; static bool force;
static bool show_period; static bool show_period;
static bool show_formula; static bool show_formula;
...@@ -741,7 +740,8 @@ static const struct option options[] = { ...@@ -741,7 +740,8 @@ static const struct option options[] = {
OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]", OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
"only consider these symbols"), "only consider these symbols"),
OPT_STRING('s', "sort", &sort_order, "key[,key2...]", OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
"sort by key(s): pid, comm, dso, symbol, parent"), "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
" Please refer the man page for the complete list."),
OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator", OPT_STRING('t', "field-separator", &symbol_conf.field_sep, "separator",
"separator for columns, no spaces will be added between " "separator for columns, no spaces will be added between "
"columns '.' is reserved."), "columns '.' is reserved."),
...@@ -1141,7 +1141,6 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1141,7 +1141,6 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
{ {
perf_config(perf_default_config, NULL); perf_config(perf_default_config, NULL);
sort_order = diff__default_sort_order;
argc = parse_options(argc, argv, options, diff_usage, 0); argc = parse_options(argc, argv, options, diff_usage, 0);
if (symbol__init() < 0) if (symbol__init() < 0)
...@@ -1152,6 +1151,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1152,6 +1151,8 @@ int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
ui_init(); ui_init();
sort__mode = SORT_MODE__DIFF;
if (setup_sorting() < 0) if (setup_sorting() < 0)
usage_with_options(diff_usage, options); usage_with_options(diff_usage, options);
......
...@@ -699,10 +699,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -699,10 +699,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_BOOLEAN(0, "header-only", &report.header_only, OPT_BOOLEAN(0, "header-only", &report.header_only,
"Show only data header."), "Show only data header."),
OPT_STRING('s', "sort", &sort_order, "key[,key2...]", OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
"sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline," "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
" dso_to, dso_from, symbol_to, symbol_from, mispredict," " Please refer the man page for the complete list."),
" weight, local_weight, mem, symbol_daddr, dso_daddr, tlb, " OPT_STRING('F', "fields", &field_order, "key[,keys...]",
"snoop, locked, abort, in_tx, transaction"), "output field(s): overhead, period, sample plus all of sort keys"),
OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization, OPT_BOOLEAN(0, "showcpuutilization", &symbol_conf.show_cpu_utilization,
"Show sample percentage for different cpu modes"), "Show sample percentage for different cpu modes"),
OPT_STRING('p', "parent", &parent_pattern, "regex", OPT_STRING('p', "parent", &parent_pattern, "regex",
...@@ -807,39 +807,20 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -807,39 +807,20 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
if (branch_mode == -1 && has_br_stack) if (branch_mode == -1 && has_br_stack)
sort__mode = SORT_MODE__BRANCH; sort__mode = SORT_MODE__BRANCH;
/* sort__mode could be NORMAL if --no-branch-stack */
if (sort__mode == SORT_MODE__BRANCH) {
/*
* if no sort_order is provided, then specify
* branch-mode specific order
*/
if (sort_order == default_sort_order)
sort_order = "comm,dso_from,symbol_from,"
"dso_to,symbol_to";
}
if (report.mem_mode) { if (report.mem_mode) {
if (sort__mode == SORT_MODE__BRANCH) { if (sort__mode == SORT_MODE__BRANCH) {
pr_err("branch and mem mode incompatible\n"); pr_err("branch and mem mode incompatible\n");
goto error; goto error;
} }
sort__mode = SORT_MODE__MEMORY; sort__mode = SORT_MODE__MEMORY;
/*
* if no sort_order is provided, then specify
* branch-mode specific order
*/
if (sort_order == default_sort_order)
sort_order = "local_weight,mem,sym,dso,symbol_daddr,dso_daddr,snoop,tlb,locked";
} }
if (setup_sorting() < 0) { if (setup_sorting() < 0) {
if (sort_order)
parse_options_usage(report_usage, options, "s", 1); parse_options_usage(report_usage, options, "s", 1);
goto error; if (field_order)
} parse_options_usage(sort_order ? NULL : report_usage,
options, "F", 1);
if (parent_pattern != default_parent_pattern) {
if (sort_dimension__add("parent") < 0)
goto error; goto error;
} }
...@@ -849,10 +830,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -849,10 +830,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
if (strcmp(input_name, "-") != 0) if (strcmp(input_name, "-") != 0)
setup_browser(true); setup_browser(true);
else { else
use_browser = 0; use_browser = 0;
perf_hpp__init();
}
if (report.header || report.header_only) { if (report.header || report.header_only) {
perf_session__fprintf_info(session, stdout, perf_session__fprintf_info(session, stdout,
......
...@@ -1083,8 +1083,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1083,8 +1083,10 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_INCR('v', "verbose", &verbose, OPT_INCR('v', "verbose", &verbose,
"be more verbose (show counter open errors, etc)"), "be more verbose (show counter open errors, etc)"),
OPT_STRING('s', "sort", &sort_order, "key[,key2...]", OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
"sort by key(s): pid, comm, dso, symbol, parent, weight, local_weight," "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
" abort, in_tx, transaction"), " Please refer the man page for the complete list."),
OPT_STRING(0, "fields", &field_order, "key[,keys...]",
"output field(s): overhead, period, sample plus all of sort keys"),
OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples, OPT_BOOLEAN('n', "show-nr-samples", &symbol_conf.show_nr_samples,
"Show a column with the number of samples"), "Show a column with the number of samples"),
OPT_CALLBACK_NOOPT('g', NULL, &top.record_opts, OPT_CALLBACK_NOOPT('g', NULL, &top.record_opts,
...@@ -1137,17 +1139,19 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1137,17 +1139,19 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
if (argc) if (argc)
usage_with_options(top_usage, options); usage_with_options(top_usage, options);
if (sort_order == default_sort_order) sort__mode = SORT_MODE__TOP;
sort_order = "dso,symbol"; /* display thread wants entries to be collapsed in a different tree */
sort__need_collapse = 1;
if (setup_sorting() < 0) { if (setup_sorting() < 0) {
if (sort_order)
parse_options_usage(top_usage, options, "s", 1); parse_options_usage(top_usage, options, "s", 1);
if (field_order)
parse_options_usage(sort_order ? NULL : top_usage,
options, "fields", 0);
goto out_delete_evlist; goto out_delete_evlist;
} }
/* display thread wants entries to be collapsed in a different tree */
sort__need_collapse = 1;
if (top.use_stdio) if (top.use_stdio)
use_browser = 0; use_browser = 0;
else if (top.use_tui) else if (top.use_tui)
......
...@@ -135,6 +135,10 @@ static struct test { ...@@ -135,6 +135,10 @@ static struct test {
.desc = "Test thread mg sharing", .desc = "Test thread mg sharing",
.func = test__thread_mg_share, .func = test__thread_mg_share,
}, },
{
.desc = "Test output sorting of hist entries",
.func = test__hists_output,
},
{ {
.func = NULL, .func = NULL,
}, },
......
...@@ -146,3 +146,60 @@ struct machine *setup_fake_machine(struct machines *machines) ...@@ -146,3 +146,60 @@ struct machine *setup_fake_machine(struct machines *machines)
machine__delete(machine); machine__delete(machine);
return NULL; return NULL;
} }
void print_hists_in(struct hists *hists)
{
int i = 0;
struct rb_root *root;
struct rb_node *node;
if (sort__need_collapse)
root = &hists->entries_collapsed;
else
root = hists->entries_in;
pr_info("----- %s --------\n", __func__);
node = rb_first(root);
while (node) {
struct hist_entry *he;
he = rb_entry(node, struct hist_entry, rb_node_in);
if (!he->filtered) {
pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n",
i, thread__comm_str(he->thread),
he->ms.map->dso->short_name,
he->ms.sym->name, he->stat.period);
}
i++;
node = rb_next(node);
}
}
void print_hists_out(struct hists *hists)
{
int i = 0;
struct rb_root *root;
struct rb_node *node;
root = &hists->entries;
pr_info("----- %s --------\n", __func__);
node = rb_first(root);
while (node) {
struct hist_entry *he;
he = rb_entry(node, struct hist_entry, rb_node);
if (!he->filtered) {
pr_info("%2d: entry: %8s:%5d [%-8s] %20s: period = %"PRIu64"\n",
i, thread__comm_str(he->thread), he->thread->tid,
he->ms.map->dso->short_name,
he->ms.sym->name, he->stat.period);
}
i++;
node = rb_next(node);
}
}
...@@ -41,4 +41,7 @@ struct machines; ...@@ -41,4 +41,7 @@ struct machines;
*/ */
struct machine *setup_fake_machine(struct machines *machines); struct machine *setup_fake_machine(struct machines *machines);
void print_hists_in(struct hists *hists);
void print_hists_out(struct hists *hists);
#endif /* __PERF_TESTS__HISTS_COMMON_H__ */ #endif /* __PERF_TESTS__HISTS_COMMON_H__ */
...@@ -98,33 +98,6 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine) ...@@ -98,33 +98,6 @@ static int add_hist_entries(struct perf_evlist *evlist, struct machine *machine)
return TEST_FAIL; return TEST_FAIL;
} }
static void print_hists(struct hists *hists)
{
int i = 0;
struct rb_root *root;
struct rb_node *node;
root = &hists->entries;
pr_info("----- %s --------\n", __func__);
node = rb_first(root);
while (node) {
struct hist_entry *he;
he = rb_entry(node, struct hist_entry, rb_node);
if (!he->filtered) {
pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n",
i, thread__comm_str(he->thread),
he->ms.map->dso->short_name,
he->ms.sym->name, he->stat.period);
}
i++;
node = rb_next(node);
}
}
int test__hists_filter(void) int test__hists_filter(void)
{ {
int err = TEST_FAIL; int err = TEST_FAIL;
...@@ -169,7 +142,7 @@ int test__hists_filter(void) ...@@ -169,7 +142,7 @@ int test__hists_filter(void)
if (verbose > 2) { if (verbose > 2) {
pr_info("Normal histogram\n"); pr_info("Normal histogram\n");
print_hists(hists); print_hists_out(hists);
} }
TEST_ASSERT_VAL("Invalid nr samples", TEST_ASSERT_VAL("Invalid nr samples",
...@@ -193,7 +166,7 @@ int test__hists_filter(void) ...@@ -193,7 +166,7 @@ int test__hists_filter(void)
if (verbose > 2) { if (verbose > 2) {
pr_info("Histogram for thread filter\n"); pr_info("Histogram for thread filter\n");
print_hists(hists); print_hists_out(hists);
} }
/* normal stats should be invariant */ /* normal stats should be invariant */
...@@ -222,7 +195,7 @@ int test__hists_filter(void) ...@@ -222,7 +195,7 @@ int test__hists_filter(void)
if (verbose > 2) { if (verbose > 2) {
pr_info("Histogram for dso filter\n"); pr_info("Histogram for dso filter\n");
print_hists(hists); print_hists_out(hists);
} }
/* normal stats should be invariant */ /* normal stats should be invariant */
...@@ -257,7 +230,7 @@ int test__hists_filter(void) ...@@ -257,7 +230,7 @@ int test__hists_filter(void)
if (verbose > 2) { if (verbose > 2) {
pr_info("Histogram for symbol filter\n"); pr_info("Histogram for symbol filter\n");
print_hists(hists); print_hists_out(hists);
} }
/* normal stats should be invariant */ /* normal stats should be invariant */
...@@ -284,7 +257,7 @@ int test__hists_filter(void) ...@@ -284,7 +257,7 @@ int test__hists_filter(void)
if (verbose > 2) { if (verbose > 2) {
pr_info("Histogram for all filters\n"); pr_info("Histogram for all filters\n");
print_hists(hists); print_hists_out(hists);
} }
/* normal stats should be invariant */ /* normal stats should be invariant */
...@@ -310,6 +283,7 @@ int test__hists_filter(void) ...@@ -310,6 +283,7 @@ int test__hists_filter(void)
out: out:
/* tear down everything */ /* tear down everything */
perf_evlist__delete(evlist); perf_evlist__delete(evlist);
reset_output_field();
machines__exit(&machines); machines__exit(&machines);
return err; return err;
......
...@@ -268,33 +268,6 @@ static int validate_link(struct hists *leader, struct hists *other) ...@@ -268,33 +268,6 @@ static int validate_link(struct hists *leader, struct hists *other)
return __validate_link(leader, 0) || __validate_link(other, 1); return __validate_link(leader, 0) || __validate_link(other, 1);
} }
static void print_hists(struct hists *hists)
{
int i = 0;
struct rb_root *root;
struct rb_node *node;
if (sort__need_collapse)
root = &hists->entries_collapsed;
else
root = hists->entries_in;
pr_info("----- %s --------\n", __func__);
node = rb_first(root);
while (node) {
struct hist_entry *he;
he = rb_entry(node, struct hist_entry, rb_node_in);
pr_info("%2d: entry: %-8s [%-8s] %20s: period = %"PRIu64"\n",
i, thread__comm_str(he->thread), he->ms.map->dso->short_name,
he->ms.sym->name, he->stat.period);
i++;
node = rb_next(node);
}
}
int test__hists_link(void) int test__hists_link(void)
{ {
int err = -1; int err = -1;
...@@ -336,7 +309,7 @@ int test__hists_link(void) ...@@ -336,7 +309,7 @@ int test__hists_link(void)
hists__collapse_resort(&evsel->hists, NULL); hists__collapse_resort(&evsel->hists, NULL);
if (verbose > 2) if (verbose > 2)
print_hists(&evsel->hists); print_hists_in(&evsel->hists);
} }
first = perf_evlist__first(evlist); first = perf_evlist__first(evlist);
...@@ -359,6 +332,7 @@ int test__hists_link(void) ...@@ -359,6 +332,7 @@ int test__hists_link(void)
out: out:
/* tear down everything */ /* tear down everything */
perf_evlist__delete(evlist); perf_evlist__delete(evlist);
reset_output_field();
machines__exit(&machines); machines__exit(&machines);
return err; return err;
......
This diff is collapsed.
...@@ -44,6 +44,7 @@ int test__dwarf_unwind(void); ...@@ -44,6 +44,7 @@ int test__dwarf_unwind(void);
int test__hists_filter(void); int test__hists_filter(void);
int test__mmap_thread_lookup(void); int test__mmap_thread_lookup(void);
int test__thread_mg_share(void); int test__thread_mg_share(void);
int test__hists_output(void);
#if defined(__x86_64__) || defined(__i386__) || defined(__arm__) #if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
#ifdef HAVE_DWARF_UNWIND_SUPPORT #ifdef HAVE_DWARF_UNWIND_SUPPORT
......
...@@ -616,35 +616,6 @@ struct hpp_arg { ...@@ -616,35 +616,6 @@ struct hpp_arg {
bool current_entry; bool current_entry;
}; };
static int __hpp__overhead_callback(struct perf_hpp *hpp, bool front)
{
struct hpp_arg *arg = hpp->ptr;
if (arg->current_entry && arg->b->navkeypressed)
ui_browser__set_color(arg->b, HE_COLORSET_SELECTED);
else
ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
if (front) {
if (!symbol_conf.use_callchain)
return 0;
slsmg_printf("%c ", arg->folded_sign);
return 2;
}
return 0;
}
static int __hpp__color_callback(struct perf_hpp *hpp, bool front __maybe_unused)
{
struct hpp_arg *arg = hpp->ptr;
if (!arg->current_entry || !arg->b->navkeypressed)
ui_browser__set_color(arg->b, HE_COLORSET_NORMAL);
return 0;
}
static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
{ {
struct hpp_arg *arg = hpp->ptr; struct hpp_arg *arg = hpp->ptr;
...@@ -665,7 +636,7 @@ static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...) ...@@ -665,7 +636,7 @@ static int __hpp__slsmg_color_printf(struct perf_hpp *hpp, const char *fmt, ...)
return ret; return ret;
} }
#define __HPP_COLOR_PERCENT_FN(_type, _field, _cb) \ #define __HPP_COLOR_PERCENT_FN(_type, _field) \
static u64 __hpp_get_##_field(struct hist_entry *he) \ static u64 __hpp_get_##_field(struct hist_entry *he) \
{ \ { \
return he->stat._field; \ return he->stat._field; \
...@@ -676,22 +647,20 @@ hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\ ...@@ -676,22 +647,20 @@ hist_browser__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,\
struct perf_hpp *hpp, \ struct perf_hpp *hpp, \
struct hist_entry *he) \ struct hist_entry *he) \
{ \ { \
return __hpp__fmt(hpp, he, __hpp_get_##_field, _cb, " %6.2f%%", \ return __hpp__fmt(hpp, he, __hpp_get_##_field, " %6.2f%%", \
__hpp__slsmg_color_printf, true); \ __hpp__slsmg_color_printf, true); \
} }
__HPP_COLOR_PERCENT_FN(overhead, period, __hpp__overhead_callback) __HPP_COLOR_PERCENT_FN(overhead, period)
__HPP_COLOR_PERCENT_FN(overhead_sys, period_sys, __hpp__color_callback) __HPP_COLOR_PERCENT_FN(overhead_sys, period_sys)
__HPP_COLOR_PERCENT_FN(overhead_us, period_us, __hpp__color_callback) __HPP_COLOR_PERCENT_FN(overhead_us, period_us)
__HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys, __hpp__color_callback) __HPP_COLOR_PERCENT_FN(overhead_guest_sys, period_guest_sys)
__HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us, __hpp__color_callback) __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
#undef __HPP_COLOR_PERCENT_FN #undef __HPP_COLOR_PERCENT_FN
void hist_browser__init_hpp(void) void hist_browser__init_hpp(void)
{ {
perf_hpp__init();
perf_hpp__format[PERF_HPP__OVERHEAD].color = perf_hpp__format[PERF_HPP__OVERHEAD].color =
hist_browser__hpp_color_overhead; hist_browser__hpp_color_overhead;
perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
...@@ -742,11 +711,27 @@ static int hist_browser__show_entry(struct hist_browser *browser, ...@@ -742,11 +711,27 @@ static int hist_browser__show_entry(struct hist_browser *browser,
ui_browser__gotorc(&browser->b, row, 0); ui_browser__gotorc(&browser->b, row, 0);
perf_hpp__for_each_format(fmt) { perf_hpp__for_each_format(fmt) {
if (!first) { if (perf_hpp__should_skip(fmt))
slsmg_printf(" "); continue;
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);
}
if (first) {
if (symbol_conf.use_callchain) {
slsmg_printf("%c ", folded_sign);
width -= 2; width -= 2;
} }
first = false; first = false;
} else {
slsmg_printf(" ");
width -= 2;
}
if (fmt->color) { if (fmt->color) {
width -= fmt->color(fmt, &hpp, entry); width -= fmt->color(fmt, &hpp, entry);
...@@ -760,8 +745,8 @@ static int hist_browser__show_entry(struct hist_browser *browser, ...@@ -760,8 +745,8 @@ static int hist_browser__show_entry(struct hist_browser *browser,
if (!browser->b.navkeypressed) if (!browser->b.navkeypressed)
width += 1; width += 1;
hist_entry__sort_snprintf(entry, s, sizeof(s), browser->hists); slsmg_write_nstring("", width);
slsmg_write_nstring(s, width);
++row; ++row;
++printed; ++printed;
} else } else
...@@ -830,10 +815,7 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd, ...@@ -830,10 +815,7 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd,
if (total) if (total)
percent = h->stat.period * 100.0 / total; percent = h->stat.period * 100.0 / total;
if (percent < min_pcnt) if (!h->filtered && percent >= min_pcnt)
return NULL;
if (!h->filtered)
return nd; return nd;
nd = rb_next(nd); nd = rb_next(nd);
...@@ -1104,27 +1086,35 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser, ...@@ -1104,27 +1086,35 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
struct hist_entry *he, FILE *fp) struct hist_entry *he, FILE *fp)
{ {
char s[8192]; char s[8192];
double percent;
int printed = 0; int printed = 0;
char folded_sign = ' '; char folded_sign = ' ';
struct perf_hpp hpp = {
.buf = s,
.size = sizeof(s),
};
struct perf_hpp_fmt *fmt;
bool first = true;
int ret;
if (symbol_conf.use_callchain) if (symbol_conf.use_callchain)
folded_sign = hist_entry__folded(he); folded_sign = hist_entry__folded(he);
hist_entry__sort_snprintf(he, s, sizeof(s), browser->hists);
percent = (he->stat.period * 100.0) / browser->hists->stats.total_period;
if (symbol_conf.use_callchain) if (symbol_conf.use_callchain)
printed += fprintf(fp, "%c ", folded_sign); printed += fprintf(fp, "%c ", folded_sign);
printed += fprintf(fp, " %5.2f%%", percent); perf_hpp__for_each_format(fmt) {
if (perf_hpp__should_skip(fmt))
if (symbol_conf.show_nr_samples) continue;
printed += fprintf(fp, " %11u", he->stat.nr_events);
if (symbol_conf.show_total_period) if (!first) {
printed += fprintf(fp, " %12" PRIu64, he->stat.period); ret = scnprintf(hpp.buf, hpp.size, " ");
advance_hpp(&hpp, ret);
} else
first = false;
ret = fmt->entry(fmt, &hpp, he);
advance_hpp(&hpp, ret);
}
printed += fprintf(fp, "%s\n", rtrim(s)); printed += fprintf(fp, "%s\n", rtrim(s));
if (folded_sign == '-') if (folded_sign == '-')
......
...@@ -43,7 +43,7 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused, ...@@ -43,7 +43,7 @@ static int perf_gtk__hpp_color_##_type(struct perf_hpp_fmt *fmt __maybe_unused,
struct perf_hpp *hpp, \ struct perf_hpp *hpp, \
struct hist_entry *he) \ struct hist_entry *he) \
{ \ { \
return __hpp__fmt(hpp, he, he_get_##_field, NULL, " %6.2f%%", \ return __hpp__fmt(hpp, he, he_get_##_field, " %6.2f%%", \
__percent_color_snprintf, true); \ __percent_color_snprintf, true); \
} }
...@@ -58,8 +58,6 @@ __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us) ...@@ -58,8 +58,6 @@ __HPP_COLOR_PERCENT_FN(overhead_guest_us, period_guest_us)
void perf_gtk__init_hpp(void) void perf_gtk__init_hpp(void)
{ {
perf_hpp__init();
perf_hpp__format[PERF_HPP__OVERHEAD].color = perf_hpp__format[PERF_HPP__OVERHEAD].color =
perf_gtk__hpp_color_overhead; perf_gtk__hpp_color_overhead;
perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color = perf_hpp__format[PERF_HPP__OVERHEAD_SYS].color =
...@@ -153,7 +151,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, ...@@ -153,7 +151,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
struct perf_hpp_fmt *fmt; struct perf_hpp_fmt *fmt;
GType col_types[MAX_COLUMNS]; GType col_types[MAX_COLUMNS];
GtkCellRenderer *renderer; GtkCellRenderer *renderer;
struct sort_entry *se;
GtkTreeStore *store; GtkTreeStore *store;
struct rb_node *nd; struct rb_node *nd;
GtkWidget *view; GtkWidget *view;
...@@ -172,16 +169,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, ...@@ -172,16 +169,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
perf_hpp__for_each_format(fmt) perf_hpp__for_each_format(fmt)
col_types[nr_cols++] = G_TYPE_STRING; col_types[nr_cols++] = G_TYPE_STRING;
list_for_each_entry(se, &hist_entry__sort_list, list) {
if (se->elide)
continue;
if (se == &sort_sym)
sym_col = nr_cols;
col_types[nr_cols++] = G_TYPE_STRING;
}
store = gtk_tree_store_newv(nr_cols, col_types); store = gtk_tree_store_newv(nr_cols, col_types);
view = gtk_tree_view_new(); view = gtk_tree_view_new();
...@@ -191,6 +178,9 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, ...@@ -191,6 +178,9 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
col_idx = 0; col_idx = 0;
perf_hpp__for_each_format(fmt) { perf_hpp__for_each_format(fmt) {
if (perf_hpp__should_skip(fmt))
continue;
fmt->header(fmt, &hpp, hists_to_evsel(hists)); fmt->header(fmt, &hpp, hists_to_evsel(hists));
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view), gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
...@@ -199,16 +189,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, ...@@ -199,16 +189,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
col_idx++, NULL); col_idx++, NULL);
} }
list_for_each_entry(se, &hist_entry__sort_list, list) {
if (se->elide)
continue;
gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(view),
-1, se->se_header,
renderer, "text",
col_idx++, NULL);
}
for (col_idx = 0; col_idx < nr_cols; col_idx++) { for (col_idx = 0; col_idx < nr_cols; col_idx++) {
GtkTreeViewColumn *column; GtkTreeViewColumn *column;
...@@ -245,6 +225,9 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, ...@@ -245,6 +225,9 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
col_idx = 0; col_idx = 0;
perf_hpp__for_each_format(fmt) { perf_hpp__for_each_format(fmt) {
if (perf_hpp__should_skip(fmt))
continue;
if (fmt->color) if (fmt->color)
fmt->color(fmt, &hpp, h); fmt->color(fmt, &hpp, h);
else else
...@@ -253,16 +236,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, ...@@ -253,16 +236,6 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
gtk_tree_store_set(store, &iter, col_idx++, s, -1); gtk_tree_store_set(store, &iter, col_idx++, s, -1);
} }
list_for_each_entry(se, &hist_entry__sort_list, list) {
if (se->elide)
continue;
se->se_snprintf(h, s, ARRAY_SIZE(s),
hists__col_len(hists, se->se_width_idx));
gtk_tree_store_set(store, &iter, col_idx++, s, -1);
}
if (symbol_conf.use_callchain && sort__has_sym) { if (symbol_conf.use_callchain && sort__has_sym) {
if (callchain_param.mode == CHAIN_GRAPH_REL) if (callchain_param.mode == CHAIN_GRAPH_REL)
total = h->stat.period; total = h->stat.period;
......
This diff is collapsed.
...@@ -86,8 +86,6 @@ void setup_browser(bool fallback_to_pager) ...@@ -86,8 +86,6 @@ void setup_browser(bool fallback_to_pager)
use_browser = 0; use_browser = 0;
if (fallback_to_pager) if (fallback_to_pager)
setup_pager(); setup_pager();
perf_hpp__init();
break; break;
} }
} }
......
...@@ -183,7 +183,8 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, ...@@ -183,7 +183,8 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
* the symbol. No need to print it otherwise it appears as * the symbol. No need to print it otherwise it appears as
* displayed twice. * displayed twice.
*/ */
if (!i++ && sort__first_dimension == SORT_SYM) if (!i++ && field_order == NULL &&
sort_order && !prefixcmp(sort_order, "sym"))
continue; continue;
if (!printed) { if (!printed) {
ret += callchain__fprintf_left_margin(fp, left_margin); ret += callchain__fprintf_left_margin(fp, left_margin);
...@@ -296,18 +297,24 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he, ...@@ -296,18 +297,24 @@ static size_t hist_entry__callchain_fprintf(struct hist_entry *he,
int left_margin = 0; int left_margin = 0;
u64 total_period = hists->stats.total_period; u64 total_period = hists->stats.total_period;
if (sort__first_dimension == SORT_COMM) { if (field_order == NULL && (sort_order == NULL ||
struct sort_entry *se = list_first_entry(&hist_entry__sort_list, !prefixcmp(sort_order, "comm"))) {
typeof(*se), list); struct perf_hpp_fmt *fmt;
left_margin = hists__col_len(hists, se->se_width_idx);
perf_hpp__for_each_format(fmt) {
if (!perf_hpp__is_sort_entry(fmt))
continue;
/* must be 'comm' sort entry */
left_margin = fmt->width(fmt, NULL, hists_to_evsel(hists));
left_margin -= thread__comm_len(he->thread); left_margin -= thread__comm_len(he->thread);
break;
}
} }
return hist_entry_callchain__fprintf(he, total_period, left_margin, fp); return hist_entry_callchain__fprintf(he, total_period, left_margin, fp);
} }
static int hist_entry__period_snprintf(struct perf_hpp *hpp, static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
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;
...@@ -319,6 +326,9 @@ static int hist_entry__period_snprintf(struct perf_hpp *hpp, ...@@ -319,6 +326,9 @@ static int hist_entry__period_snprintf(struct perf_hpp *hpp,
return 0; return 0;
perf_hpp__for_each_format(fmt) { perf_hpp__for_each_format(fmt) {
if (perf_hpp__should_skip(fmt))
continue;
/* /*
* If there's no field_sep, we still need * If there's no field_sep, we still need
* to display initial ' '. * to display initial ' '.
...@@ -353,8 +363,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size, ...@@ -353,8 +363,7 @@ static int hist_entry__fprintf(struct hist_entry *he, size_t size,
if (size == 0 || size > bfsz) if (size == 0 || size > bfsz)
size = hpp.size = bfsz; size = hpp.size = bfsz;
ret = hist_entry__period_snprintf(&hpp, he); hist_entry__snprintf(he, &hpp);
hist_entry__sort_snprintf(he, bf + ret, size - ret, hists);
ret = fprintf(fp, "%s\n", bf); ret = fprintf(fp, "%s\n", bf);
...@@ -368,12 +377,10 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, ...@@ -368,12 +377,10 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
int max_cols, float min_pcnt, FILE *fp) int max_cols, float min_pcnt, FILE *fp)
{ {
struct perf_hpp_fmt *fmt; struct perf_hpp_fmt *fmt;
struct sort_entry *se;
struct rb_node *nd; struct rb_node *nd;
size_t ret = 0; size_t ret = 0;
unsigned int width; unsigned int width;
const char *sep = symbol_conf.field_sep; const char *sep = symbol_conf.field_sep;
const char *col_width = symbol_conf.col_width_list_str;
int nr_rows = 0; int nr_rows = 0;
char bf[96]; char bf[96];
struct perf_hpp dummy_hpp = { struct perf_hpp dummy_hpp = {
...@@ -386,12 +393,19 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, ...@@ -386,12 +393,19 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
init_rem_hits(); init_rem_hits();
perf_hpp__for_each_format(fmt)
perf_hpp__reset_width(fmt, hists);
if (!show_header) if (!show_header)
goto print_entries; goto print_entries;
fprintf(fp, "# "); fprintf(fp, "# ");
perf_hpp__for_each_format(fmt) { perf_hpp__for_each_format(fmt) {
if (perf_hpp__should_skip(fmt))
continue;
if (!first) if (!first)
fprintf(fp, "%s", sep ?: " "); fprintf(fp, "%s", sep ?: " ");
else else
...@@ -401,28 +415,6 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, ...@@ -401,28 +415,6 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
fprintf(fp, "%s", bf); fprintf(fp, "%s", bf);
} }
list_for_each_entry(se, &hist_entry__sort_list, list) {
if (se->elide)
continue;
if (sep) {
fprintf(fp, "%c%s", *sep, se->se_header);
continue;
}
width = strlen(se->se_header);
if (symbol_conf.col_width_list_str) {
if (col_width) {
hists__set_col_len(hists, se->se_width_idx,
atoi(col_width));
col_width = strchr(col_width, ',');
if (col_width)
++col_width;
}
}
if (!hists__new_col_len(hists, se->se_width_idx, width))
width = hists__col_len(hists, se->se_width_idx);
fprintf(fp, " %*s", width, se->se_header);
}
fprintf(fp, "\n"); fprintf(fp, "\n");
if (max_rows && ++nr_rows >= max_rows) if (max_rows && ++nr_rows >= max_rows)
goto out; goto out;
...@@ -437,6 +429,9 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, ...@@ -437,6 +429,9 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
perf_hpp__for_each_format(fmt) { perf_hpp__for_each_format(fmt) {
unsigned int i; unsigned int i;
if (perf_hpp__should_skip(fmt))
continue;
if (!first) if (!first)
fprintf(fp, "%s", sep ?: " "); fprintf(fp, "%s", sep ?: " ");
else else
...@@ -447,20 +442,6 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows, ...@@ -447,20 +442,6 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
fprintf(fp, "."); fprintf(fp, ".");
} }
list_for_each_entry(se, &hist_entry__sort_list, list) {
unsigned int i;
if (se->elide)
continue;
fprintf(fp, " ");
width = hists__col_len(hists, se->se_width_idx);
if (width == 0)
width = strlen(se->se_header);
for (i = 0; i < width; i++)
fprintf(fp, ".");
}
fprintf(fp, "\n"); fprintf(fp, "\n");
if (max_rows && ++nr_rows >= max_rows) if (max_rows && ++nr_rows >= max_rows)
goto out; goto out;
......
...@@ -432,11 +432,14 @@ struct hist_entry *__hists__add_entry(struct hists *hists, ...@@ -432,11 +432,14 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
int64_t int64_t
hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
{ {
struct sort_entry *se; struct perf_hpp_fmt *fmt;
int64_t cmp = 0; int64_t cmp = 0;
list_for_each_entry(se, &hist_entry__sort_list, list) { perf_hpp__for_each_sort_list(fmt) {
cmp = se->se_cmp(left, right); if (perf_hpp__should_skip(fmt))
continue;
cmp = fmt->cmp(left, right);
if (cmp) if (cmp)
break; break;
} }
...@@ -447,15 +450,14 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right) ...@@ -447,15 +450,14 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
int64_t int64_t
hist_entry__collapse(struct hist_entry *left, struct hist_entry *right) hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
{ {
struct sort_entry *se; struct perf_hpp_fmt *fmt;
int64_t cmp = 0; int64_t cmp = 0;
list_for_each_entry(se, &hist_entry__sort_list, list) { perf_hpp__for_each_sort_list(fmt) {
int64_t (*f)(struct hist_entry *, struct hist_entry *); if (perf_hpp__should_skip(fmt))
continue;
f = se->se_collapse ?: se->se_cmp;
cmp = f(left, right); cmp = fmt->collapse(left, right);
if (cmp) if (cmp)
break; break;
} }
...@@ -568,64 +570,21 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog) ...@@ -568,64 +570,21 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
} }
} }
/* static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
* reverse the map, sort on period.
*/
static int period_cmp(u64 period_a, u64 period_b)
{ {
if (period_a > period_b) struct perf_hpp_fmt *fmt;
return 1; int64_t cmp = 0;
if (period_a < period_b)
return -1;
return 0;
}
static int hist_entry__sort_on_period(struct hist_entry *a,
struct hist_entry *b)
{
int ret;
int i, nr_members;
struct perf_evsel *evsel;
struct hist_entry *pair;
u64 *periods_a, *periods_b;
ret = period_cmp(a->stat.period, b->stat.period);
if (ret || !symbol_conf.event_group)
return ret;
evsel = hists_to_evsel(a->hists);
nr_members = evsel->nr_members;
if (nr_members <= 1)
return ret;
periods_a = zalloc(sizeof(periods_a) * nr_members);
periods_b = zalloc(sizeof(periods_b) * nr_members);
if (!periods_a || !periods_b)
goto out;
list_for_each_entry(pair, &a->pairs.head, pairs.node) {
evsel = hists_to_evsel(pair->hists);
periods_a[perf_evsel__group_idx(evsel)] = pair->stat.period;
}
list_for_each_entry(pair, &b->pairs.head, pairs.node) { perf_hpp__for_each_sort_list(fmt) {
evsel = hists_to_evsel(pair->hists); if (perf_hpp__should_skip(fmt))
periods_b[perf_evsel__group_idx(evsel)] = pair->stat.period; continue;
}
for (i = 1; i < nr_members; i++) { cmp = fmt->sort(a, b);
ret = period_cmp(periods_a[i], periods_b[i]); if (cmp)
if (ret)
break; break;
} }
out: return cmp;
free(periods_a);
free(periods_b);
return ret;
} }
static void hists__reset_filter_stats(struct hists *hists) static void hists__reset_filter_stats(struct hists *hists)
...@@ -673,7 +632,7 @@ static void __hists__insert_output_entry(struct rb_root *entries, ...@@ -673,7 +632,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
parent = *p; parent = *p;
iter = rb_entry(parent, struct hist_entry, rb_node); iter = rb_entry(parent, struct hist_entry, rb_node);
if (hist_entry__sort_on_period(he, iter) > 0) if (hist_entry__sort(he, iter) > 0)
p = &(*p)->rb_left; p = &(*p)->rb_left;
else else
p = &(*p)->rb_right; p = &(*p)->rb_right;
......
...@@ -160,15 +160,29 @@ struct perf_hpp_fmt { ...@@ -160,15 +160,29 @@ struct perf_hpp_fmt {
struct hist_entry *he); struct hist_entry *he);
int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp, int (*entry)(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
struct hist_entry *he); struct hist_entry *he);
int64_t (*cmp)(struct hist_entry *a, struct hist_entry *b);
int64_t (*collapse)(struct hist_entry *a, struct hist_entry *b);
int64_t (*sort)(struct hist_entry *a, struct hist_entry *b);
struct list_head list; struct list_head list;
struct list_head sort_list;
}; };
extern struct list_head perf_hpp__list; extern struct list_head perf_hpp__list;
extern struct list_head perf_hpp__sort_list;
#define perf_hpp__for_each_format(format) \ #define perf_hpp__for_each_format(format) \
list_for_each_entry(format, &perf_hpp__list, list) list_for_each_entry(format, &perf_hpp__list, list)
#define perf_hpp__for_each_format_safe(format, tmp) \
list_for_each_entry_safe(format, tmp, &perf_hpp__list, list)
#define perf_hpp__for_each_sort_list(format) \
list_for_each_entry(format, &perf_hpp__sort_list, sort_list)
#define perf_hpp__for_each_sort_list_safe(format, tmp) \
list_for_each_entry_safe(format, tmp, &perf_hpp__sort_list, sort_list)
extern struct perf_hpp_fmt perf_hpp__format[]; extern struct perf_hpp_fmt perf_hpp__format[];
enum { enum {
...@@ -187,14 +201,23 @@ enum { ...@@ -187,14 +201,23 @@ enum {
void perf_hpp__init(void); void perf_hpp__init(void);
void perf_hpp__column_register(struct perf_hpp_fmt *format); void perf_hpp__column_register(struct perf_hpp_fmt *format);
void perf_hpp__column_enable(unsigned col); void perf_hpp__column_enable(unsigned col);
void perf_hpp__register_sort_field(struct perf_hpp_fmt *format);
void perf_hpp__setup_output_field(void);
void perf_hpp__reset_output_field(void);
void perf_hpp__append_sort_keys(void);
bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format);
bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
bool perf_hpp__should_skip(struct perf_hpp_fmt *format);
void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists);
typedef u64 (*hpp_field_fn)(struct hist_entry *he); typedef u64 (*hpp_field_fn)(struct hist_entry *he);
typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front); typedef int (*hpp_callback_fn)(struct perf_hpp *hpp, bool front);
typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...); typedef int (*hpp_snprint_fn)(struct perf_hpp *hpp, const char *fmt, ...);
int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
hpp_field_fn get_field, hpp_callback_fn callback, hpp_field_fn get_field, const char *fmt,
const char *fmt, hpp_snprint_fn print_fn, bool fmt_percent); hpp_snprint_fn print_fn, bool fmt_percent);
static inline void advance_hpp(struct perf_hpp *hpp, int inc) static inline void advance_hpp(struct perf_hpp *hpp, int inc)
{ {
......
...@@ -32,6 +32,93 @@ static inline int is_no_dso_memory(const char *filename) ...@@ -32,6 +32,93 @@ static inline int is_no_dso_memory(const char *filename)
!strcmp(filename, "[heap]"); !strcmp(filename, "[heap]");
} }
static inline int is_android_lib(const char *filename)
{
return !strncmp(filename, "/data/app-lib", 13) ||
!strncmp(filename, "/system/lib", 11);
}
static inline bool replace_android_lib(const char *filename, char *newfilename)
{
const char *libname;
char *app_abi;
size_t app_abi_length, new_length;
size_t lib_length = 0;
libname = strrchr(filename, '/');
if (libname)
lib_length = strlen(libname);
app_abi = getenv("APP_ABI");
if (!app_abi)
return false;
app_abi_length = strlen(app_abi);
if (!strncmp(filename, "/data/app-lib", 13)) {
char *apk_path;
if (!app_abi_length)
return false;
new_length = 7 + app_abi_length + lib_length;
apk_path = getenv("APK_PATH");
if (apk_path) {
new_length += strlen(apk_path) + 1;
if (new_length > PATH_MAX)
return false;
snprintf(newfilename, new_length,
"%s/libs/%s/%s", apk_path, app_abi, libname);
} else {
if (new_length > PATH_MAX)
return false;
snprintf(newfilename, new_length,
"libs/%s/%s", app_abi, libname);
}
return true;
}
if (!strncmp(filename, "/system/lib/", 11)) {
char *ndk, *app;
const char *arch;
size_t ndk_length;
size_t app_length;
ndk = getenv("NDK_ROOT");
app = getenv("APP_PLATFORM");
if (!(ndk && app))
return false;
ndk_length = strlen(ndk);
app_length = strlen(app);
if (!(ndk_length && app_length && app_abi_length))
return false;
arch = !strncmp(app_abi, "arm", 3) ? "arm" :
!strncmp(app_abi, "mips", 4) ? "mips" :
!strncmp(app_abi, "x86", 3) ? "x86" : NULL;
if (!arch)
return false;
new_length = 27 + ndk_length +
app_length + lib_length
+ strlen(arch);
if (new_length > PATH_MAX)
return false;
snprintf(newfilename, new_length,
"%s/platforms/%s/arch-%s/usr/lib/%s",
ndk, app, arch, libname);
return true;
}
return false;
}
void map__init(struct map *map, enum map_type type, void map__init(struct map *map, enum map_type type,
u64 start, u64 end, u64 pgoff, struct dso *dso) u64 start, u64 end, u64 pgoff, struct dso *dso)
{ {
...@@ -59,8 +146,9 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, ...@@ -59,8 +146,9 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
if (map != NULL) { if (map != NULL) {
char newfilename[PATH_MAX]; char newfilename[PATH_MAX];
struct dso *dso; struct dso *dso;
int anon, no_dso, vdso; int anon, no_dso, vdso, android;
android = is_android_lib(filename);
anon = is_anon_memory(filename); anon = is_anon_memory(filename);
vdso = is_vdso_map(filename); vdso = is_vdso_map(filename);
no_dso = is_no_dso_memory(filename); no_dso = is_no_dso_memory(filename);
...@@ -75,6 +163,11 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, ...@@ -75,6 +163,11 @@ struct map *map__new(struct list_head *dsos__list, u64 start, u64 len,
filename = newfilename; filename = newfilename;
} }
if (android) {
if (replace_android_lib(filename, newfilename))
filename = newfilename;
}
if (vdso) { if (vdso) {
pgoff = 0; pgoff = 0;
dso = vdso__dso_findnew(dsos__list); dso = vdso__dso_findnew(dsos__list);
......
...@@ -57,13 +57,13 @@ void setup_pager(void) ...@@ -57,13 +57,13 @@ void setup_pager(void)
} }
if (!pager) if (!pager)
pager = getenv("PAGER"); pager = getenv("PAGER");
if (!pager) { if (!(pager || access("/usr/bin/pager", X_OK)))
if (!access("/usr/bin/pager", X_OK))
pager = "/usr/bin/pager"; pager = "/usr/bin/pager";
} if (!(pager || access("/usr/bin/less", X_OK)))
pager = "/usr/bin/less";
if (!pager) if (!pager)
pager = "less"; pager = "cat";
else if (!*pager || !strcmp(pager, "cat")) if (!*pager || !strcmp(pager, "cat"))
return; return;
spawned_pager = 1; /* means we are emitting to terminal */ spawned_pager = 1; /* means we are emitting to terminal */
......
This diff is collapsed.
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
extern regex_t parent_regex; extern regex_t parent_regex;
extern const char *sort_order; extern const char *sort_order;
extern const char *field_order;
extern const char default_parent_pattern[]; extern const char default_parent_pattern[];
extern const char *parent_pattern; extern const char *parent_pattern;
extern const char default_sort_order[]; extern const char default_sort_order[];
...@@ -133,6 +134,8 @@ enum sort_mode { ...@@ -133,6 +134,8 @@ enum sort_mode {
SORT_MODE__NORMAL, SORT_MODE__NORMAL,
SORT_MODE__BRANCH, SORT_MODE__BRANCH,
SORT_MODE__MEMORY, SORT_MODE__MEMORY,
SORT_MODE__TOP,
SORT_MODE__DIFF,
}; };
enum sort_type { enum sort_type {
...@@ -179,6 +182,7 @@ struct sort_entry { ...@@ -179,6 +182,7 @@ struct sort_entry {
int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *); int64_t (*se_cmp)(struct hist_entry *, struct hist_entry *);
int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *); int64_t (*se_collapse)(struct hist_entry *, struct hist_entry *);
int64_t (*se_sort)(struct hist_entry *, struct hist_entry *);
int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size, int (*se_snprintf)(struct hist_entry *he, char *bf, size_t size,
unsigned int width); unsigned int width);
u8 se_width_idx; u8 se_width_idx;
...@@ -189,6 +193,8 @@ extern struct sort_entry sort_thread; ...@@ -189,6 +193,8 @@ extern struct sort_entry sort_thread;
extern struct list_head hist_entry__sort_list; extern struct list_head hist_entry__sort_list;
int setup_sorting(void); int setup_sorting(void);
int setup_output_field(void);
void reset_output_field(void);
extern int sort_dimension__add(const char *); extern int sort_dimension__add(const char *);
void sort__setup_elide(FILE *fp); void sort__setup_elide(FILE *fp);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment