summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@kernel.org>2016-02-04 10:58:01 +0300
committerIngo Molnar <mingo@kernel.org>2016-02-04 10:58:01 +0300
commitd3aaf09f889b31f3b424bf9603b163ec1204c361 (patch)
treed5ef0fe7c7c3996a8d5dd4aba7093f0d319c299e /tools
parentb83ea91f08f648460b08e8980560abdf96060a19 (diff)
parentb62e8dfcda8cb133c062c0e1207afea2476eb7fd (diff)
downloadlinux-d3aaf09f889b31f3b424bf9603b163ec1204c361.tar.xz
Merge tag 'perf-core-for-mingo' 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: New features: - Add 'L' hotkey to dynamicly set the percent threshold for histogram entries and callchains, i.e. dynamicly do what the --percent-limit command line option to 'top' and 'report' does. (Namhyung Kim) Infrastructure changes: - Per hists field and sort lists, that will be used, for instance, in the c2c tool (Jiri Olsa) Documentation changes: - Update documentation of --sort and --perf-limit options for 'perf report' (Namhyung Kim) Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Documentation/perf-report.txt37
-rw-r--r--tools/perf/builtin-annotate.c2
-rw-r--r--tools/perf/builtin-report.c20
-rw-r--r--tools/perf/builtin-top.c24
-rw-r--r--tools/perf/tests/hists_cumulate.c2
-rw-r--r--tools/perf/tests/hists_filter.c2
-rw-r--r--tools/perf/tests/hists_output.c10
-rw-r--r--tools/perf/ui/browsers/hists.c63
-rw-r--r--tools/perf/ui/gtk/hists.c6
-rw-r--r--tools/perf/ui/hist.c170
-rw-r--r--tools/perf/ui/stdio/hist.c8
-rw-r--r--tools/perf/util/hist.c47
-rw-r--r--tools/perf/util/hist.h65
-rw-r--r--tools/perf/util/sort.c205
14 files changed, 425 insertions, 236 deletions
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 8a301f6afb37..89cab84e92fd 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -117,6 +117,22 @@ OPTIONS
And default sort keys are changed to comm, dso_from, symbol_from, dso_to
and symbol_to, see '--branch-stack'.
+ If the --mem-mode option is used, the following sort keys are also available
+ (incompatible with --branch-stack):
+ symbol_daddr, dso_daddr, locked, tlb, mem, snoop, dcacheline.
+
+ - symbol_daddr: name of data symbol being executed on at the time of sample
+ - dso_daddr: name of library or module containing the data being executed
+ on at the time of the sample
+ - locked: whether the bus was locked at the time of the sample
+ - tlb: type of tlb access for the data at the time of the sample
+ - mem: type of memory access for the data at the time of the sample
+ - snoop: type of snoop (if any) for the data at the time of the sample
+ - dcacheline: the cacheline the data address is on at the time of the sample
+
+ And the default sort keys are changed to local_weight, mem, sym, dso,
+ symbol_daddr, dso_daddr, snoop, tlb, locked, see '--mem-mode'.
+
If the data file has tracepoint event(s), following (dynamic) sort keys
are also available:
trace, trace_fields, [<event>.]<field>[/raw]
@@ -151,22 +167,6 @@ OPTIONS
By default, every sort keys not specified in -F will be appended
automatically.
- If --mem-mode option is used, following sort keys are also available
- (incompatible with --branch-stack):
- symbol_daddr, dso_daddr, locked, tlb, mem, snoop, dcacheline.
-
- - symbol_daddr: name of data symbol being executed on at the time of sample
- - dso_daddr: name of library or module containing the data being executed
- on at the time of sample
- - locked: whether the bus was locked at the time of sample
- - tlb: type of tlb access for the data at the time of sample
- - mem: type of memory access for the data at the time of sample
- - snoop: type of snoop (if any) for the data at the time of sample
- - dcacheline: the cacheline the data address is on at the time of sample
-
- And default sort keys are changed to local_weight, mem, sym, dso,
- symbol_daddr, dso_daddr, snoop, tlb, locked, see '--mem-mode'.
-
-p::
--parent=<regex>::
A regex filter to identify parent. The parent is a caller of this
@@ -351,7 +351,10 @@ OPTIONS
--percent-limit::
Do not show entries which have an overhead under that percent.
- (Default: 0).
+ (Default: 0). Note that this option also sets the percent limit (threshold)
+ of callchains. However the default value of callchain threshold is
+ different than the default value of hist entries. Please see the
+ --call-graph option for details.
--percentage::
Determine how to display the overhead percentage of filtered entries.
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index cc5c1267c738..cfe366375c4b 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -245,7 +245,7 @@ static int __cmd_annotate(struct perf_annotate *ann)
hists__collapse_resort(hists, NULL);
/* Don't sort callchain */
perf_evsel__reset_sample_bit(pos, CALLCHAIN);
- hists__output_resort(hists, NULL);
+ perf_evsel__output_resort(pos, NULL);
if (symbol_conf.event_group &&
!perf_evsel__is_group_leader(pos))
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 72ed0b46d5a1..1eab50ac1ef6 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -507,7 +507,7 @@ static void report__output_resort(struct report *rep)
ui_progress__init(&prog, rep->nr_entries, "Sorting events for output...");
evlist__for_each(rep->session->evlist, pos)
- hists__output_resort(evsel__hists(pos), &prog);
+ perf_evsel__output_resort(pos, &prog);
ui_progress__finish();
}
@@ -912,15 +912,6 @@ repeat:
symbol_conf.cumulate_callchain = false;
}
- if (setup_sorting(session->evlist) < 0) {
- if (sort_order)
- parse_options_usage(report_usage, options, "s", 1);
- if (field_order)
- parse_options_usage(sort_order ? NULL : report_usage,
- options, "F", 1);
- goto error;
- }
-
/* Force tty output for header output and per-thread stat. */
if (report.header || report.header_only || report.show_threads)
use_browser = 0;
@@ -930,6 +921,15 @@ repeat:
else
use_browser = 0;
+ if (setup_sorting(session->evlist) < 0) {
+ if (sort_order)
+ parse_options_usage(report_usage, options, "s", 1);
+ if (field_order)
+ parse_options_usage(sort_order ? NULL : report_usage,
+ options, "F", 1);
+ goto error;
+ }
+
if (report.header || report.header_only) {
perf_session__fprintf_info(session, stdout,
report.show_full_info);
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c
index bf01cbb0ef23..a75de3940b97 100644
--- a/tools/perf/builtin-top.c
+++ b/tools/perf/builtin-top.c
@@ -252,7 +252,8 @@ static void perf_top__print_sym_table(struct perf_top *top)
char bf[160];
int printed = 0;
const int win_width = top->winsize.ws_col - 1;
- struct hists *hists = evsel__hists(top->sym_evsel);
+ struct perf_evsel *evsel = top->sym_evsel;
+ struct hists *hists = evsel__hists(evsel);
puts(CONSOLE_CLEAR);
@@ -288,7 +289,7 @@ static void perf_top__print_sym_table(struct perf_top *top)
}
hists__collapse_resort(hists, NULL);
- hists__output_resort(hists, NULL);
+ perf_evsel__output_resort(evsel, NULL);
hists__output_recalc_col_len(hists, top->print_entries - printed);
putchar('\n');
@@ -540,6 +541,7 @@ static bool perf_top__handle_keypress(struct perf_top *top, int c)
static void perf_top__sort_new_samples(void *arg)
{
struct perf_top *t = arg;
+ struct perf_evsel *evsel = t->sym_evsel;
struct hists *hists;
perf_top__reset_sample_counters(t);
@@ -547,7 +549,7 @@ static void perf_top__sort_new_samples(void *arg)
if (t->evlist->selected != NULL)
t->sym_evsel = t->evlist->selected;
- hists = evsel__hists(t->sym_evsel);
+ hists = evsel__hists(evsel);
if (t->evlist->enabled) {
if (t->zero) {
@@ -559,7 +561,7 @@ static void perf_top__sort_new_samples(void *arg)
}
hists__collapse_resort(hists, NULL);
- hists__output_resort(hists, NULL);
+ perf_evsel__output_resort(evsel, NULL);
}
static void *display_thread_tui(void *arg)
@@ -1243,6 +1245,13 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
/* display thread wants entries to be collapsed in a different tree */
sort__need_collapse = 1;
+ if (top.use_stdio)
+ use_browser = 0;
+ else if (top.use_tui)
+ use_browser = 1;
+
+ setup_browser(false);
+
if (setup_sorting(top.evlist) < 0) {
if (sort_order)
parse_options_usage(top_usage, options, "s", 1);
@@ -1252,13 +1261,6 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
goto out_delete_evlist;
}
- if (top.use_stdio)
- use_browser = 0;
- else if (top.use_tui)
- use_browser = 1;
-
- setup_browser(false);
-
status = target__validate(target);
if (status) {
target__strerror(target, status, errbuf, BUFSIZ);
diff --git a/tools/perf/tests/hists_cumulate.c b/tools/perf/tests/hists_cumulate.c
index 5e6a86e50fb9..ecf136c385d5 100644
--- a/tools/perf/tests/hists_cumulate.c
+++ b/tools/perf/tests/hists_cumulate.c
@@ -191,7 +191,7 @@ static int do_test(struct hists *hists, struct result *expected, size_t nr_expec
* function since TEST_ASSERT_VAL() returns in case of failure.
*/
hists__collapse_resort(hists, NULL);
- hists__output_resort(hists, NULL);
+ perf_evsel__output_resort(hists_to_evsel(hists), NULL);
if (verbose > 2) {
pr_info("use callchain: %d, cumulate callchain: %d\n",
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index 351a42463444..34b945a55d4d 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -145,7 +145,7 @@ int test__hists_filter(int subtest __maybe_unused)
struct hists *hists = evsel__hists(evsel);
hists__collapse_resort(hists, NULL);
- hists__output_resort(hists, NULL);
+ perf_evsel__output_resort(evsel, NULL);
if (verbose > 2) {
pr_info("Normal histogram\n");
diff --git a/tools/perf/tests/hists_output.c b/tools/perf/tests/hists_output.c
index b231265148d8..23cce67c7e48 100644
--- a/tools/perf/tests/hists_output.c
+++ b/tools/perf/tests/hists_output.c
@@ -156,7 +156,7 @@ static int test1(struct perf_evsel *evsel, struct machine *machine)
goto out;
hists__collapse_resort(hists, NULL);
- hists__output_resort(hists, NULL);
+ perf_evsel__output_resort(evsel, NULL);
if (verbose > 2) {
pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@@ -256,7 +256,7 @@ static int test2(struct perf_evsel *evsel, struct machine *machine)
goto out;
hists__collapse_resort(hists, NULL);
- hists__output_resort(hists, NULL);
+ perf_evsel__output_resort(evsel, NULL);
if (verbose > 2) {
pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@@ -310,7 +310,7 @@ static int test3(struct perf_evsel *evsel, struct machine *machine)
goto out;
hists__collapse_resort(hists, NULL);
- hists__output_resort(hists, NULL);
+ perf_evsel__output_resort(evsel, NULL);
if (verbose > 2) {
pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@@ -388,7 +388,7 @@ static int test4(struct perf_evsel *evsel, struct machine *machine)
goto out;
hists__collapse_resort(hists, NULL);
- hists__output_resort(hists, NULL);
+ perf_evsel__output_resort(evsel, NULL);
if (verbose > 2) {
pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
@@ -491,7 +491,7 @@ static int test5(struct perf_evsel *evsel, struct machine *machine)
goto out;
hists__collapse_resort(hists, NULL);
- hists__output_resort(hists, NULL);
+ perf_evsel__output_resort(evsel, NULL);
if (verbose > 2) {
pr_info("[fields = %s, sort = %s]\n", field_order, sort_order);
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index 61d578bf4ffd..a5a5390476ac 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -1095,7 +1095,7 @@ static int hist_browser__show_entry(struct hist_browser *browser,
hist_browser__gotorc(browser, row, 0);
- perf_hpp__for_each_format(fmt) {
+ hists__for_each_format(browser->hists, fmt) {
if (perf_hpp__should_skip(fmt, entry->hists) ||
column++ < browser->b.horiz_scroll)
continue;
@@ -1175,7 +1175,7 @@ static int hists_browser__scnprintf_headers(struct hist_browser *browser, char *
return ret;
}
- perf_hpp__for_each_format(fmt) {
+ hists__for_each_format(browser->hists, fmt) {
if (perf_hpp__should_skip(fmt, hists) || column++ < browser->b.horiz_scroll)
continue;
@@ -1441,7 +1441,7 @@ static int hist_browser__fprintf_entry(struct hist_browser *browser,
if (symbol_conf.use_callchain)
printed += fprintf(fp, "%c ", folded_sign);
- perf_hpp__for_each_format(fmt) {
+ hists__for_each_format(browser->hists, fmt) {
if (perf_hpp__should_skip(fmt, he->hists))
continue;
@@ -2029,6 +2029,42 @@ static void hist_browser__update_nr_entries(struct hist_browser *hb)
hb->nr_non_filtered_entries = nr_entries;
}
+static void hist_browser__update_percent_limit(struct hist_browser *hb,
+ double percent)
+{
+ struct hist_entry *he;
+ struct rb_node *nd = rb_first(&hb->hists->entries);
+ u64 total = hists__total_period(hb->hists);
+ u64 min_callchain_hits = total * (percent / 100);
+
+ hb->min_pcnt = callchain_param.min_percent = percent;
+
+ if (!symbol_conf.use_callchain)
+ return;
+
+ while ((nd = hists__filter_entries(nd, hb->min_pcnt)) != NULL) {
+ he = rb_entry(nd, struct hist_entry, rb_node);
+
+ if (callchain_param.mode == CHAIN_GRAPH_REL) {
+ total = he->stat.period;
+
+ if (symbol_conf.cumulate_callchain)
+ total = he->stat_acc->period;
+
+ min_callchain_hits = total * (percent / 100);
+ }
+
+ callchain_param.sort(&he->sorted_chain, he->callchain,
+ min_callchain_hits, &callchain_param);
+
+ /* force to re-evaluate folding state of callchains */
+ he->init_have_children = false;
+ hist_entry__set_folding(he, false);
+
+ nd = rb_next(nd);
+ }
+}
+
static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
const char *helpline,
bool left_exits,
@@ -2064,6 +2100,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
"E Expand all callchains\n" \
"F Toggle percentage of filtered entries\n" \
"H Display column headers\n" \
+ "L Change percent limit\n" \
"m Display context menu\n" \
"S Zoom into current Processor Socket\n" \
@@ -2104,7 +2141,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
memset(options, 0, sizeof(options));
memset(actions, 0, sizeof(actions));
- perf_hpp__for_each_format(fmt) {
+ hists__for_each_format(browser->hists, fmt) {
perf_hpp__reset_width(fmt, hists);
/*
* This is done just once, and activates the horizontal scrolling
@@ -2219,6 +2256,24 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
top->zero = !top->zero;
}
continue;
+ case 'L':
+ if (ui_browser__input_window("Percent Limit",
+ "Please enter the value you want to hide entries under that percent.",
+ buf, "ENTER: OK, ESC: Cancel",
+ delay_secs * 2) == K_ENTER) {
+ char *end;
+ double new_percent = strtod(buf, &end);
+
+ if (new_percent < 0 || new_percent > 100) {
+ ui_browser__warning(&browser->b, delay_secs * 2,
+ "Invalid percent: %.2f", new_percent);
+ continue;
+ }
+
+ hist_browser__update_percent_limit(browser, new_percent);
+ hist_browser__reset(browser);
+ }
+ continue;
case K_F1:
case 'h':
case '?':
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index 0f8dcfdfb10f..32cc38a5b57f 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -306,7 +306,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
nr_cols = 0;
- perf_hpp__for_each_format(fmt)
+ hists__for_each_format(hists, fmt)
col_types[nr_cols++] = G_TYPE_STRING;
store = gtk_tree_store_newv(nr_cols, col_types);
@@ -317,7 +317,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
col_idx = 0;
- perf_hpp__for_each_format(fmt) {
+ hists__for_each_format(hists, fmt) {
if (perf_hpp__should_skip(fmt, hists))
continue;
@@ -367,7 +367,7 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
col_idx = 0;
- perf_hpp__for_each_format(fmt) {
+ hists__for_each_format(hists, fmt) {
if (perf_hpp__should_skip(fmt, h->hists))
continue;
diff --git a/tools/perf/ui/hist.c b/tools/perf/ui/hist.c
index bf2a66e254ea..1ba4117d9c2d 100644
--- a/tools/perf/ui/hist.c
+++ b/tools/perf/ui/hist.c
@@ -371,7 +371,20 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
return 0;
}
-#define HPP__COLOR_PRINT_FNS(_name, _fn) \
+static bool perf_hpp__is_hpp_entry(struct perf_hpp_fmt *a)
+{
+ return a->header == hpp__header_fn;
+}
+
+static bool hpp__equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
+{
+ if (!perf_hpp__is_hpp_entry(a) || !perf_hpp__is_hpp_entry(b))
+ return false;
+
+ return a->idx == b->idx;
+}
+
+#define HPP__COLOR_PRINT_FNS(_name, _fn, _idx) \
{ \
.name = _name, \
.header = hpp__header_fn, \
@@ -381,9 +394,11 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
.cmp = hpp__nop_cmp, \
.collapse = hpp__nop_cmp, \
.sort = hpp__sort_ ## _fn, \
+ .idx = PERF_HPP__ ## _idx, \
+ .equal = hpp__equal, \
}
-#define HPP__COLOR_ACC_PRINT_FNS(_name, _fn) \
+#define HPP__COLOR_ACC_PRINT_FNS(_name, _fn, _idx) \
{ \
.name = _name, \
.header = hpp__header_fn, \
@@ -393,9 +408,11 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
.cmp = hpp__nop_cmp, \
.collapse = hpp__nop_cmp, \
.sort = hpp__sort_ ## _fn, \
+ .idx = PERF_HPP__ ## _idx, \
+ .equal = hpp__equal, \
}
-#define HPP__PRINT_FNS(_name, _fn) \
+#define HPP__PRINT_FNS(_name, _fn, _idx) \
{ \
.name = _name, \
.header = hpp__header_fn, \
@@ -404,22 +421,25 @@ static int64_t hpp__nop_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
.cmp = hpp__nop_cmp, \
.collapse = hpp__nop_cmp, \
.sort = hpp__sort_ ## _fn, \
+ .idx = PERF_HPP__ ## _idx, \
+ .equal = hpp__equal, \
}
struct perf_hpp_fmt perf_hpp__format[] = {
- HPP__COLOR_PRINT_FNS("Overhead", overhead),
- HPP__COLOR_PRINT_FNS("sys", overhead_sys),
- HPP__COLOR_PRINT_FNS("usr", overhead_us),
- HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys),
- HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us),
- HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc),
- HPP__PRINT_FNS("Samples", samples),
- HPP__PRINT_FNS("Period", period)
+ HPP__COLOR_PRINT_FNS("Overhead", overhead, OVERHEAD),
+ HPP__COLOR_PRINT_FNS("sys", overhead_sys, OVERHEAD_SYS),
+ HPP__COLOR_PRINT_FNS("usr", overhead_us, OVERHEAD_US),
+ HPP__COLOR_PRINT_FNS("guest sys", overhead_guest_sys, OVERHEAD_GUEST_SYS),
+ HPP__COLOR_PRINT_FNS("guest usr", overhead_guest_us, OVERHEAD_GUEST_US),
+ HPP__COLOR_ACC_PRINT_FNS("Children", overhead_acc, OVERHEAD_ACC),
+ HPP__PRINT_FNS("Samples", samples, SAMPLES),
+ HPP__PRINT_FNS("Period", period, PERIOD)
};
-LIST_HEAD(perf_hpp__list);
-LIST_HEAD(perf_hpp__sort_list);
-
+struct perf_hpp_list perf_hpp_list = {
+ .fields = LIST_HEAD_INIT(perf_hpp_list.fields),
+ .sorts = LIST_HEAD_INIT(perf_hpp_list.sorts),
+};
#undef HPP__COLOR_PRINT_FNS
#undef HPP__COLOR_ACC_PRINT_FNS
@@ -485,63 +505,60 @@ void perf_hpp__init(void)
hpp_dimension__add_output(PERF_HPP__PERIOD);
}
-void perf_hpp__column_register(struct perf_hpp_fmt *format)
-{
- list_add_tail(&format->list, &perf_hpp__list);
-}
-
-void perf_hpp__column_unregister(struct perf_hpp_fmt *format)
-{
- list_del(&format->list);
-}
-
-void perf_hpp__register_sort_field(struct perf_hpp_fmt *format)
+void perf_hpp_list__column_register(struct perf_hpp_list *list,
+ struct perf_hpp_fmt *format)
{
- list_add_tail(&format->sort_list, &perf_hpp__sort_list);
+ list_add_tail(&format->list, &list->fields);
}
-void perf_hpp__column_enable(unsigned col)
+void perf_hpp_list__register_sort_field(struct perf_hpp_list *list,
+ struct perf_hpp_fmt *format)
{
- BUG_ON(col >= PERF_HPP__MAX_INDEX);
- perf_hpp__column_register(&perf_hpp__format[col]);
+ list_add_tail(&format->sort_list, &list->sorts);
}
-void perf_hpp__column_disable(unsigned col)
+void perf_hpp__column_unregister(struct perf_hpp_fmt *format)
{
- BUG_ON(col >= PERF_HPP__MAX_INDEX);
- perf_hpp__column_unregister(&perf_hpp__format[col]);
+ list_del(&format->list);
}
void perf_hpp__cancel_cumulate(void)
{
+ struct perf_hpp_fmt *fmt, *acc, *ovh, *tmp;
+
if (is_strict_order(field_order))
return;
- perf_hpp__column_disable(PERF_HPP__OVERHEAD_ACC);
- perf_hpp__format[PERF_HPP__OVERHEAD].name = "Overhead";
+ ovh = &perf_hpp__format[PERF_HPP__OVERHEAD];
+ acc = &perf_hpp__format[PERF_HPP__OVERHEAD_ACC];
+
+ perf_hpp_list__for_each_format_safe(&perf_hpp_list, fmt, tmp) {
+ if (acc->equal(acc, fmt)) {
+ perf_hpp__column_unregister(fmt);
+ continue;
+ }
+
+ if (ovh->equal(ovh, fmt))
+ fmt->name = "Overhead";
+ }
+}
+
+static bool fmt_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
+{
+ return a->equal && a->equal(a, b);
}
-void perf_hpp__setup_output_field(void)
+void perf_hpp__setup_output_field(struct perf_hpp_list *list)
{
struct perf_hpp_fmt *fmt;
/* append sort keys to output field */
- perf_hpp__for_each_sort_list(fmt) {
- if (!list_empty(&fmt->list))
- continue;
-
- /*
- * sort entry fields are dynamically created,
- * so they can share a same sort key even though
- * the list is empty.
- */
- if (perf_hpp__is_sort_entry(fmt)) {
- struct perf_hpp_fmt *pos;
+ perf_hpp_list__for_each_sort_list(list, fmt) {
+ struct perf_hpp_fmt *pos;
- perf_hpp__for_each_format(pos) {
- if (perf_hpp__same_sort_entry(pos, fmt))
- goto next;
- }
+ perf_hpp_list__for_each_format(list, pos) {
+ if (fmt_equal(fmt, pos))
+ goto next;
}
perf_hpp__column_register(fmt);
@@ -550,27 +567,17 @@ next:
}
}
-void perf_hpp__append_sort_keys(void)
+void perf_hpp__append_sort_keys(struct perf_hpp_list *list)
{
struct perf_hpp_fmt *fmt;
/* append output fields to sort keys */
- perf_hpp__for_each_format(fmt) {
- if (!list_empty(&fmt->sort_list))
- continue;
+ perf_hpp_list__for_each_format(list, fmt) {
+ struct perf_hpp_fmt *pos;
- /*
- * sort entry fields are dynamically created,
- * so they can share a same sort key even though
- * the list is empty.
- */
- if (perf_hpp__is_sort_entry(fmt)) {
- struct perf_hpp_fmt *pos;
-
- perf_hpp__for_each_sort_list(pos) {
- if (perf_hpp__same_sort_entry(pos, fmt))
- goto next;
- }
+ perf_hpp_list__for_each_sort_list(list, pos) {
+ if (fmt_equal(fmt, pos))
+ goto next;
}
perf_hpp__register_sort_field(fmt);
@@ -579,20 +586,29 @@ next:
}
}
-void perf_hpp__reset_output_field(void)
+
+static void fmt_free(struct perf_hpp_fmt *fmt)
+{
+ if (fmt->free)
+ fmt->free(fmt);
+}
+
+void perf_hpp__reset_output_field(struct perf_hpp_list *list)
{
struct perf_hpp_fmt *fmt, *tmp;
/* reset output fields */
- perf_hpp__for_each_format_safe(fmt, tmp) {
+ perf_hpp_list__for_each_format_safe(list, fmt, tmp) {
list_del_init(&fmt->list);
list_del_init(&fmt->sort_list);
+ fmt_free(fmt);
}
/* reset sort keys */
- perf_hpp__for_each_sort_list_safe(fmt, tmp) {
+ perf_hpp_list__for_each_sort_list_safe(list, fmt, tmp) {
list_del_init(&fmt->list);
list_del_init(&fmt->sort_list);
+ fmt_free(fmt);
}
}
@@ -606,7 +622,7 @@ unsigned int hists__sort_list_width(struct hists *hists)
bool first = true;
struct perf_hpp dummy_hpp;
- perf_hpp__for_each_format(fmt) {
+ hists__for_each_format(hists, fmt) {
if (perf_hpp__should_skip(fmt, hists))
continue;
@@ -626,20 +642,12 @@ unsigned int hists__sort_list_width(struct hists *hists)
void perf_hpp__reset_width(struct perf_hpp_fmt *fmt, struct hists *hists)
{
- int idx;
-
if (perf_hpp__is_sort_entry(fmt))
return perf_hpp__reset_sort_width(fmt, hists);
- for (idx = 0; idx < PERF_HPP__MAX_INDEX; idx++) {
- if (fmt == &perf_hpp__format[idx])
- break;
- }
-
- if (idx == PERF_HPP__MAX_INDEX)
- return;
+ BUG_ON(fmt->idx >= PERF_HPP__MAX_INDEX);
- switch (idx) {
+ switch (fmt->idx) {
case PERF_HPP__OVERHEAD:
case PERF_HPP__OVERHEAD_SYS:
case PERF_HPP__OVERHEAD_US:
@@ -667,7 +675,7 @@ void perf_hpp__set_user_width(const char *width_list_str)
struct perf_hpp_fmt *fmt;
const char *ptr = width_list_str;
- perf_hpp__for_each_format(fmt) {
+ perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
char *p;
int len = strtol(ptr, &p, 10);
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 691e52ce7510..1a6e8f7f38c4 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -384,7 +384,7 @@ static int hist_entry__snprintf(struct hist_entry *he, struct perf_hpp *hpp)
if (symbol_conf.exclude_other && !he->parent)
return 0;
- perf_hpp__for_each_format(fmt) {
+ hists__for_each_format(he->hists, fmt) {
if (perf_hpp__should_skip(fmt, he->hists))
continue;
@@ -453,7 +453,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
init_rem_hits();
- perf_hpp__for_each_format(fmt)
+ hists__for_each_format(hists, fmt)
perf_hpp__reset_width(fmt, hists);
if (symbol_conf.col_width_list_str)
@@ -464,7 +464,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
fprintf(fp, "# ");
- perf_hpp__for_each_format(fmt) {
+ hists__for_each_format(hists, fmt) {
if (perf_hpp__should_skip(fmt, hists))
continue;
@@ -488,7 +488,7 @@ size_t hists__fprintf(struct hists *hists, bool show_header, int max_rows,
fprintf(fp, "# ");
- perf_hpp__for_each_format(fmt) {
+ hists__for_each_format(hists, fmt) {
unsigned int i;
if (perf_hpp__should_skip(fmt, hists))
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 098310bc4489..12f2d794dc28 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -958,10 +958,11 @@ out:
int64_t
hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
{
+ struct hists *hists = left->hists;
struct perf_hpp_fmt *fmt;
int64_t cmp = 0;
- perf_hpp__for_each_sort_list(fmt) {
+ hists__for_each_sort_list(hists, fmt) {
cmp = fmt->cmp(fmt, left, right);
if (cmp)
break;
@@ -973,10 +974,11 @@ hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
int64_t
hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
{
+ struct hists *hists = left->hists;
struct perf_hpp_fmt *fmt;
int64_t cmp = 0;
- perf_hpp__for_each_sort_list(fmt) {
+ hists__for_each_sort_list(hists, fmt) {
cmp = fmt->collapse(fmt, left, right);
if (cmp)
break;
@@ -1117,10 +1119,11 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
static int hist_entry__sort(struct hist_entry *a, struct hist_entry *b)
{
+ struct hists *hists = a->hists;
struct perf_hpp_fmt *fmt;
int64_t cmp = 0;
- perf_hpp__for_each_sort_list(fmt) {
+ hists__for_each_sort_list(hists, fmt) {
if (perf_hpp__should_skip(fmt, a->hists))
continue;
@@ -1197,19 +1200,13 @@ static void __hists__insert_output_entry(struct rb_root *entries,
rb_insert_color(&he->rb_node, entries);
}
-void hists__output_resort(struct hists *hists, struct ui_progress *prog)
+static void output_resort(struct hists *hists, struct ui_progress *prog,
+ bool use_callchain)
{
struct rb_root *root;
struct rb_node *next;
struct hist_entry *n;
u64 min_callchain_hits;
- struct perf_evsel *evsel = hists_to_evsel(hists);
- bool use_callchain;
-
- if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph)
- use_callchain = evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN;
- else
- use_callchain = symbol_conf.use_callchain;
min_callchain_hits = hists__total_period(hists) * (callchain_param.min_percent / 100);
@@ -1239,6 +1236,23 @@ void hists__output_resort(struct hists *hists, struct ui_progress *prog)
}
}
+void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog)
+{
+ bool use_callchain;
+
+ if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph)
+ use_callchain = evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN;
+ else
+ use_callchain = symbol_conf.use_callchain;
+
+ output_resort(evsel__hists(evsel), prog, use_callchain);
+}
+
+void hists__output_resort(struct hists *hists, struct ui_progress *prog)
+{
+ output_resort(hists, prog, symbol_conf.use_callchain);
+}
+
static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h,
enum hist_filter filter)
{
@@ -1567,7 +1581,7 @@ int perf_hist_config(const char *var, const char *value)
return 0;
}
-int __hists__init(struct hists *hists)
+int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list)
{
memset(hists, 0, sizeof(*hists));
hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
@@ -1576,6 +1590,7 @@ int __hists__init(struct hists *hists)
hists->entries = RB_ROOT;
pthread_mutex_init(&hists->lock, NULL);
hists->socket_filter = -1;
+ hists->hpp_list = hpp_list;
return 0;
}
@@ -1612,7 +1627,7 @@ static int hists_evsel__init(struct perf_evsel *evsel)
{
struct hists *hists = evsel__hists(evsel);
- __hists__init(hists);
+ __hists__init(hists, &perf_hpp_list);
return 0;
}
@@ -1631,3 +1646,9 @@ int hists__init(void)
return err;
}
+
+void perf_hpp_list__init(struct perf_hpp_list *list)
+{
+ INIT_LIST_HEAD(&list->fields);
+ INIT_LIST_HEAD(&list->sorts);
+}
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index d4ec4822a103..1c7544a8fe1a 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -75,6 +75,7 @@ struct hists {
u64 event_stream;
u16 col_len[HISTC_NR_COLS];
int socket_filter;
+ struct perf_hpp_list *hpp_list;
};
struct hist_entry_iter;
@@ -128,6 +129,7 @@ int hist_entry__sort_snprintf(struct hist_entry *he, char *bf, size_t size,
struct hists *hists);
void hist_entry__delete(struct hist_entry *he);
+void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *prog);
void hists__output_resort(struct hists *hists, struct ui_progress *prog);
void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
@@ -185,7 +187,7 @@ static inline struct hists *evsel__hists(struct perf_evsel *evsel)
}
int hists__init(void);
-int __hists__init(struct hists *hists);
+int __hists__init(struct hists *hists, struct perf_hpp_list *hpp_list);
struct rb_root *hists__get_rotate_entries_in(struct hists *hists);
bool hists__collapse_insert_entry(struct hists *hists __maybe_unused,
@@ -214,28 +216,56 @@ struct perf_hpp_fmt {
struct hist_entry *a, struct hist_entry *b);
int64_t (*sort)(struct perf_hpp_fmt *fmt,
struct hist_entry *a, struct hist_entry *b);
+ bool (*equal)(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b);
+ void (*free)(struct perf_hpp_fmt *fmt);
struct list_head list;
struct list_head sort_list;
bool elide;
int len;
int user_len;
+ int idx;
};
-extern struct list_head perf_hpp__list;
-extern struct list_head perf_hpp__sort_list;
+struct perf_hpp_list {
+ struct list_head fields;
+ struct list_head sorts;
+};
+
+extern struct perf_hpp_list perf_hpp_list;
+
+void perf_hpp_list__column_register(struct perf_hpp_list *list,
+ struct perf_hpp_fmt *format);
+void perf_hpp_list__register_sort_field(struct perf_hpp_list *list,
+ struct perf_hpp_fmt *format);
+
+static inline void perf_hpp__column_register(struct perf_hpp_fmt *format)
+{
+ perf_hpp_list__column_register(&perf_hpp_list, format);
+}
-#define perf_hpp__for_each_format(format) \
- list_for_each_entry(format, &perf_hpp__list, list)
+static inline void perf_hpp__register_sort_field(struct perf_hpp_fmt *format)
+{
+ perf_hpp_list__register_sort_field(&perf_hpp_list, format);
+}
+
+#define perf_hpp_list__for_each_format(_list, format) \
+ list_for_each_entry(format, &(_list)->fields, list)
-#define perf_hpp__for_each_format_safe(format, tmp) \
- list_for_each_entry_safe(format, tmp, &perf_hpp__list, list)
+#define perf_hpp_list__for_each_format_safe(_list, format, tmp) \
+ list_for_each_entry_safe(format, tmp, &(_list)->fields, list)
-#define perf_hpp__for_each_sort_list(format) \
- list_for_each_entry(format, &perf_hpp__sort_list, sort_list)
+#define perf_hpp_list__for_each_sort_list(_list, format) \
+ list_for_each_entry(format, &(_list)->sorts, 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)
+#define perf_hpp_list__for_each_sort_list_safe(_list, format, tmp) \
+ list_for_each_entry_safe(format, tmp, &(_list)->sorts, sort_list)
+
+#define hists__for_each_format(hists, format) \
+ perf_hpp_list__for_each_format((hists)->hpp_list, fmt)
+
+#define hists__for_each_sort_list(hists, format) \
+ perf_hpp_list__for_each_sort_list((hists)->hpp_list, fmt)
extern struct perf_hpp_fmt perf_hpp__format[];
@@ -254,19 +284,14 @@ enum {
};
void perf_hpp__init(void);
-void perf_hpp__column_register(struct perf_hpp_fmt *format);
void perf_hpp__column_unregister(struct perf_hpp_fmt *format);
-void perf_hpp__column_enable(unsigned col);
-void perf_hpp__column_disable(unsigned col);
void perf_hpp__cancel_cumulate(void);
+void perf_hpp__setup_output_field(struct perf_hpp_list *list);
+void perf_hpp__reset_output_field(struct perf_hpp_list *list);
+void perf_hpp__append_sort_keys(struct perf_hpp_list *list);
-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__is_dynamic_entry(struct perf_hpp_fmt *format);
bool perf_hpp__defined_dynamic_entry(struct perf_hpp_fmt *fmt, struct hists *hists);
@@ -381,4 +406,6 @@ int parse_filter_percentage(const struct option *opt __maybe_unused,
const char *arg, int unset __maybe_unused);
int perf_hist_config(const char *var, const char *value);
+void perf_hpp_list__init(struct perf_hpp_list *list);
+
#endif /* __PERF_HIST_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 898e4b0724bf..de620f7f40f4 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -1441,20 +1441,6 @@ struct hpp_sort_entry {
struct sort_entry *se;
};
-bool perf_hpp__same_sort_entry(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
-{
- struct hpp_sort_entry *hse_a;
- struct hpp_sort_entry *hse_b;
-
- if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
- return false;
-
- hse_a = container_of(a, struct hpp_sort_entry, hpp);
- hse_b = container_of(b, struct hpp_sort_entry, hpp);
-
- return hse_a->se == hse_b->se;
-}
-
void perf_hpp__reset_sort_width(struct perf_hpp_fmt *fmt, struct hists *hists)
{
struct hpp_sort_entry *hse;
@@ -1540,6 +1526,33 @@ static int64_t __sort__hpp_sort(struct perf_hpp_fmt *fmt,
return sort_fn(a, b);
}
+bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
+{
+ return format->header == __sort__hpp_header;
+}
+
+static bool __sort__hpp_equal(struct perf_hpp_fmt *a, struct perf_hpp_fmt *b)
+{
+ struct hpp_sort_entry *hse_a;
+ struct hpp_sort_entry *hse_b;
+
+ if (!perf_hpp__is_sort_entry(a) || !perf_hpp__is_sort_entry(b))
+ return false;
+
+ hse_a = container_of(a, struct hpp_sort_entry, hpp);
+ hse_b = container_of(b, struct hpp_sort_entry, hpp);
+
+ return hse_a->se == hse_b->se;
+}
+
+static void hse_free(struct perf_hpp_fmt *fmt)
+{
+ struct hpp_sort_entry *hse;
+
+ hse = container_of(fmt, struct hpp_sort_entry, hpp);
+ free(hse);
+}
+
static struct hpp_sort_entry *
__sort_dimension__alloc_hpp(struct sort_dimension *sd)
{
@@ -1561,6 +1574,8 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
hse->hpp.cmp = __sort__hpp_cmp;
hse->hpp.collapse = __sort__hpp_collapse;
hse->hpp.sort = __sort__hpp_sort;
+ hse->hpp.equal = __sort__hpp_equal;
+ hse->hpp.free = hse_free;
INIT_LIST_HEAD(&hse->hpp.list);
INIT_LIST_HEAD(&hse->hpp.sort_list);
@@ -1571,9 +1586,23 @@ __sort_dimension__alloc_hpp(struct sort_dimension *sd)
return hse;
}
-bool perf_hpp__is_sort_entry(struct perf_hpp_fmt *format)
+static void hpp_free(struct perf_hpp_fmt *fmt)
{
- return format->header == __sort__hpp_header;
+ free(fmt);
+}
+
+static struct perf_hpp_fmt *__hpp_dimension__alloc_hpp(struct hpp_dimension *hd)
+{
+ struct perf_hpp_fmt *fmt;
+
+ fmt = memdup(hd->fmt, sizeof(*fmt));
+ if (fmt) {
+ INIT_LIST_HEAD(&fmt->list);
+ INIT_LIST_HEAD(&fmt->sort_list);
+ fmt->free = hpp_free;
+ }
+
+ return fmt;
}
static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
@@ -1587,14 +1616,15 @@ static int __sort_dimension__add_hpp_sort(struct sort_dimension *sd)
return 0;
}
-static int __sort_dimension__add_hpp_output(struct sort_dimension *sd)
+static int __sort_dimension__add_hpp_output(struct perf_hpp_list *list,
+ struct sort_dimension *sd)
{
struct hpp_sort_entry *hse = __sort_dimension__alloc_hpp(sd);
if (hse == NULL)
return -1;
- perf_hpp__column_register(&hse->hpp);
+ perf_hpp_list__column_register(list, &hse->hpp);
return 0;
}
@@ -1804,6 +1834,14 @@ bool perf_hpp__is_dynamic_entry(struct perf_hpp_fmt *fmt)
return fmt->cmp == __sort__hde_cmp;
}
+static void hde_free(struct perf_hpp_fmt *fmt)
+{
+ struct hpp_dynamic_entry *hde;
+
+ hde = container_of(fmt, struct hpp_dynamic_entry, hpp);
+ free(hde);
+}
+
static struct hpp_dynamic_entry *
__alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
{
@@ -1828,6 +1866,7 @@ __alloc_dynamic_entry(struct perf_evsel *evsel, struct format_field *field)
hde->hpp.cmp = __sort__hde_cmp;
hde->hpp.collapse = __sort__hde_cmp;
hde->hpp.sort = __sort__hde_cmp;
+ hde->hpp.free = hde_free;
INIT_LIST_HEAD(&hde->hpp.list);
INIT_LIST_HEAD(&hde->hpp.sort_list);
@@ -2065,40 +2104,54 @@ static int __sort_dimension__add(struct sort_dimension *sd)
static int __hpp_dimension__add(struct hpp_dimension *hd)
{
- if (!hd->taken) {
- hd->taken = 1;
+ struct perf_hpp_fmt *fmt;
- perf_hpp__register_sort_field(hd->fmt);
- }
+ if (hd->taken)
+ return 0;
+
+ fmt = __hpp_dimension__alloc_hpp(hd);
+ if (!fmt)
+ return -1;
+
+ hd->taken = 1;
+ perf_hpp__register_sort_field(fmt);
return 0;
}
-static int __sort_dimension__add_output(struct sort_dimension *sd)
+static int __sort_dimension__add_output(struct perf_hpp_list *list,
+ struct sort_dimension *sd)
{
if (sd->taken)
return 0;
- if (__sort_dimension__add_hpp_output(sd) < 0)
+ if (__sort_dimension__add_hpp_output(list, sd) < 0)
return -1;
sd->taken = 1;
return 0;
}
-static int __hpp_dimension__add_output(struct hpp_dimension *hd)
+static int __hpp_dimension__add_output(struct perf_hpp_list *list,
+ struct hpp_dimension *hd)
{
- if (!hd->taken) {
- hd->taken = 1;
+ struct perf_hpp_fmt *fmt;
- perf_hpp__column_register(hd->fmt);
- }
+ if (hd->taken)
+ return 0;
+
+ fmt = __hpp_dimension__alloc_hpp(hd);
+ if (!fmt)
+ return -1;
+
+ hd->taken = 1;
+ perf_hpp_list__column_register(list, fmt);
return 0;
}
int hpp_dimension__add_output(unsigned col)
{
BUG_ON(col >= PERF_HPP__MAX_INDEX);
- return __hpp_dimension__add_output(&hpp_sort_dimensions[col]);
+ return __hpp_dimension__add_output(&perf_hpp_list, &hpp_sort_dimensions[col]);
}
static int sort_dimension__add(const char *tok,
@@ -2191,6 +2244,26 @@ static int sort_dimension__add(const char *tok,
return -ESRCH;
}
+static int setup_sort_list(char *str, struct perf_evlist *evlist)
+{
+ char *tmp, *tok;
+ int ret = 0;
+
+ for (tok = strtok_r(str, ", ", &tmp);
+ tok; tok = strtok_r(NULL, ", ", &tmp)) {
+ ret = sort_dimension__add(tok, evlist);
+ if (ret == -EINVAL) {
+ error("Invalid --sort key: `%s'", tok);
+ break;
+ } else if (ret == -ESRCH) {
+ error("Unknown --sort key: `%s'", tok);
+ break;
+ }
+ }
+
+ return ret;
+}
+
static const char *get_default_sort_order(struct perf_evlist *evlist)
{
const char *default_sort_orders[] = {
@@ -2285,7 +2358,7 @@ static char *setup_overhead(char *keys)
static int __setup_sorting(struct perf_evlist *evlist)
{
- char *tmp, *tok, *str;
+ char *str;
const char *sort_keys;
int ret = 0;
@@ -2323,17 +2396,7 @@ static int __setup_sorting(struct perf_evlist *evlist)
}
}
- for (tok = strtok_r(str, ", ", &tmp);
- tok; tok = strtok_r(NULL, ", ", &tmp)) {
- ret = sort_dimension__add(tok, evlist);
- if (ret == -EINVAL) {
- error("Invalid --sort key: `%s'", tok);
- break;
- } else if (ret == -ESRCH) {
- error("Unknown --sort key: `%s'", tok);
- break;
- }
- }
+ ret = setup_sort_list(str, evlist);
free(str);
return ret;
@@ -2344,7 +2407,7 @@ void perf_hpp__set_elide(int idx, bool elide)
struct perf_hpp_fmt *fmt;
struct hpp_sort_entry *hse;
- perf_hpp__for_each_format(fmt) {
+ perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
if (!perf_hpp__is_sort_entry(fmt))
continue;
@@ -2404,7 +2467,7 @@ void sort__setup_elide(FILE *output)
struct perf_hpp_fmt *fmt;
struct hpp_sort_entry *hse;
- perf_hpp__for_each_format(fmt) {
+ perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
if (!perf_hpp__is_sort_entry(fmt))
continue;
@@ -2416,7 +2479,7 @@ void sort__setup_elide(FILE *output)
* It makes no sense to elide all of sort entries.
* Just revert them to show up again.
*/
- perf_hpp__for_each_format(fmt) {
+ perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
if (!perf_hpp__is_sort_entry(fmt))
continue;
@@ -2424,7 +2487,7 @@ void sort__setup_elide(FILE *output)
return;
}
- perf_hpp__for_each_format(fmt) {
+ perf_hpp_list__for_each_format(&perf_hpp_list, fmt) {
if (!perf_hpp__is_sort_entry(fmt))
continue;
@@ -2432,7 +2495,7 @@ void sort__setup_elide(FILE *output)
}
}
-static int output_field_add(char *tok)
+static int output_field_add(struct perf_hpp_list *list, char *tok)
{
unsigned int i;
@@ -2442,7 +2505,7 @@ static int output_field_add(char *tok)
if (strncasecmp(tok, sd->name, strlen(tok)))
continue;
- return __sort_dimension__add_output(sd);
+ return __sort_dimension__add_output(list, sd);
}
for (i = 0; i < ARRAY_SIZE(hpp_sort_dimensions); i++) {
@@ -2451,7 +2514,7 @@ static int output_field_add(char *tok)
if (strncasecmp(tok, hd->name, strlen(tok)))
continue;
- return __hpp_dimension__add_output(hd);
+ return __hpp_dimension__add_output(list, hd);
}
for (i = 0; i < ARRAY_SIZE(bstack_sort_dimensions); i++) {
@@ -2460,7 +2523,7 @@ static int output_field_add(char *tok)
if (strncasecmp(tok, sd->name, strlen(tok)))
continue;
- return __sort_dimension__add_output(sd);
+ return __sort_dimension__add_output(list, sd);
}
for (i = 0; i < ARRAY_SIZE(memory_sort_dimensions); i++) {
@@ -2469,12 +2532,32 @@ static int output_field_add(char *tok)
if (strncasecmp(tok, sd->name, strlen(tok)))
continue;
- return __sort_dimension__add_output(sd);
+ return __sort_dimension__add_output(list, sd);
}
return -ESRCH;
}
+static int setup_output_list(struct perf_hpp_list *list, char *str)
+{
+ char *tmp, *tok;
+ int ret = 0;
+
+ for (tok = strtok_r(str, ", ", &tmp);
+ tok; tok = strtok_r(NULL, ", ", &tmp)) {
+ ret = output_field_add(list, tok);
+ if (ret == -EINVAL) {
+ error("Invalid --fields key: `%s'", tok);
+ break;
+ } else if (ret == -ESRCH) {
+ error("Unknown --fields key: `%s'", tok);
+ break;
+ }
+ }
+
+ return ret;
+}
+
static void reset_dimensions(void)
{
unsigned int i;
@@ -2499,7 +2582,7 @@ bool is_strict_order(const char *order)
static int __setup_output_field(void)
{
- char *tmp, *tok, *str, *strp;
+ char *str, *strp;
int ret = -EINVAL;
if (field_order == NULL)
@@ -2519,17 +2602,7 @@ static int __setup_output_field(void)
goto out;
}
- for (tok = strtok_r(strp, ", ", &tmp);
- tok; tok = strtok_r(NULL, ", ", &tmp)) {
- ret = output_field_add(tok);
- if (ret == -EINVAL) {
- error("Invalid --fields key: `%s'", tok);
- break;
- } else if (ret == -ESRCH) {
- error("Unknown --fields key: `%s'", tok);
- break;
- }
- }
+ ret = setup_output_list(&perf_hpp_list, strp);
out:
free(str);
@@ -2563,9 +2636,9 @@ int setup_sorting(struct perf_evlist *evlist)
return err;
/* copy sort keys to output fields */
- perf_hpp__setup_output_field();
+ perf_hpp__setup_output_field(&perf_hpp_list);
/* and then copy output fields to sort keys */
- perf_hpp__append_sort_keys();
+ perf_hpp__append_sort_keys(&perf_hpp_list);
return 0;
}
@@ -2581,5 +2654,5 @@ void reset_output_field(void)
sort_order = NULL;
reset_dimensions();
- perf_hpp__reset_output_field();
+ perf_hpp__reset_output_field(&perf_hpp_list);
}