Commit b3d5fc3c 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:

User visible changes:

  * Add --percentage option to control absolute/relative percentage output (Namhyung Kim)

Plumbing changes:

  * Add --list-cmds to 'kmem', 'mem', 'lock' and 'sched', for use by completion scripts (Ramkumar Ramachandra)
Signed-off-by: default avatarJiri Olsa <jolsa@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents fbdd17ec a83edb2d
...@@ -33,17 +33,20 @@ OPTIONS ...@@ -33,17 +33,20 @@ OPTIONS
-d:: -d::
--dsos=:: --dsos=::
Only consider symbols in these dsos. CSV that understands Only consider symbols in these dsos. CSV that understands
file://filename entries. file://filename entries. This option will affect the percentage
of the Baseline/Delta column. See --percentage for more info.
-C:: -C::
--comms=:: --comms=::
Only consider symbols in these comms. CSV that understands Only consider symbols in these comms. CSV that understands
file://filename entries. file://filename entries. This option will affect the percentage
of the Baseline/Delta column. See --percentage for more info.
-S:: -S::
--symbols=:: --symbols=::
Only consider these symbols. CSV that understands Only consider these symbols. CSV that understands
file://filename entries. file://filename entries. This option will affect the percentage
of the Baseline/Delta column. See --percentage for more info.
-s:: -s::
--sort=:: --sort=::
...@@ -89,6 +92,14 @@ OPTIONS ...@@ -89,6 +92,14 @@ OPTIONS
--order:: --order::
Specify compute sorting column number. Specify compute sorting column number.
--percentage::
Determine how to display the overhead percentage of filtered entries.
Filters can be applied by --comms, --dsos and/or --symbols options.
"relative" means it's relative to filtered entries only so that the
sum of shown entries will be always 100%. "absolute" means it retains
the original value before and after the filter is applied.
COMPARISON COMPARISON
---------- ----------
The comparison is governed by the baseline file. The baseline perf.data The comparison is governed by the baseline file. The baseline perf.data
...@@ -157,6 +168,10 @@ with: ...@@ -157,6 +168,10 @@ with:
- period_percent being the % of the hist entry period value within - period_percent being the % of the hist entry period value within
single data file single data file
- with filtering by -C, -d and/or -S, period_percent might be changed
relative to how entries are filtered. Use --percentage=absolute to
prevent such fluctuation.
ratio ratio
~~~~~ ~~~~~
If specified the 'Ratio' column is displayed with value 'r' computed as: If specified the 'Ratio' column is displayed with value 'r' computed as:
......
...@@ -25,10 +25,6 @@ OPTIONS ...@@ -25,10 +25,6 @@ OPTIONS
--verbose:: --verbose::
Be more verbose. (show symbol address, etc) Be more verbose. (show symbol address, etc)
-d::
--dsos=::
Only consider symbols in these dsos. CSV that understands
file://filename entries.
-n:: -n::
--show-nr-samples:: --show-nr-samples::
Show the number of samples for each symbol Show the number of samples for each symbol
...@@ -42,11 +38,18 @@ OPTIONS ...@@ -42,11 +38,18 @@ OPTIONS
-c:: -c::
--comms=:: --comms=::
Only consider symbols in these comms. CSV that understands Only consider symbols in these comms. CSV that understands
file://filename entries. file://filename entries. This option will affect the percentage of
the overhead column. See --percentage for more info.
-d::
--dsos=::
Only consider symbols in these dsos. CSV that understands
file://filename entries. This option will affect the percentage of
the overhead column. See --percentage for more info.
-S:: -S::
--symbols=:: --symbols=::
Only consider these symbols. CSV that understands Only consider these symbols. CSV that understands
file://filename entries. file://filename entries. This option will affect the percentage of
the overhead column. See --percentage for more info.
--symbol-filter=:: --symbol-filter=::
Only show symbols that match (partially) with this filter. Only show symbols that match (partially) with this filter.
...@@ -237,6 +240,15 @@ OPTIONS ...@@ -237,6 +240,15 @@ OPTIONS
Do not show entries which have an overhead under that percent. Do not show entries which have an overhead under that percent.
(Default: 0). (Default: 0).
--percentage::
Determine how to display the overhead percentage of filtered entries.
Filters can be applied by --comms, --dsos and/or --symbols options and
Zoom operations on the TUI (thread, dso, etc).
"relative" means it's relative to filtered entries only so that the
sum of shown entries will be always 100%. "absolute" means it retains
the original value before and after the filter is applied.
--header:: --header::
Show header information in the perf.data file. This includes Show header information in the perf.data file. This includes
various information like hostname, OS and perf version, cpu/mem various information like hostname, OS and perf version, cpu/mem
......
...@@ -123,13 +123,16 @@ Default is to monitor all CPUS. ...@@ -123,13 +123,16 @@ Default is to monitor all CPUS.
Show a column with the sum of periods. Show a column with the sum of periods.
--dsos:: --dsos::
Only consider symbols in these dsos. Only consider symbols in these dsos. This option will affect the
percentage of the overhead column. See --percentage for more info.
--comms:: --comms::
Only consider symbols in these comms. Only consider symbols in these comms. This option will affect the
percentage of the overhead column. See --percentage for more info.
--symbols:: --symbols::
Only consider these symbols. Only consider these symbols. This option will affect the
percentage of the overhead column. See --percentage for more info.
-M:: -M::
--disassembler-style=:: Set disassembler style for objdump. --disassembler-style=:: Set disassembler style for objdump.
...@@ -165,6 +168,15 @@ Default is to monitor all CPUS. ...@@ -165,6 +168,15 @@ Default is to monitor all CPUS.
Do not show entries which have an overhead under that percent. Do not show entries which have an overhead under that percent.
(Default: 0). (Default: 0).
--percentage::
Determine how to display the overhead percentage of filtered entries.
Filters can be applied by --comms, --dsos and/or --symbols options and
Zoom operations on the TUI (thread, dso, etc).
"relative" means it's relative to filtered entries only so that the
sum of shown entries will be always 100%. "absolute" means it retains
the original value before and after the filter is applied.
INTERACTIVE PROMPTING KEYS INTERACTIVE PROMPTING KEYS
-------------------------- --------------------------
......
...@@ -220,7 +220,8 @@ static int setup_compute(const struct option *opt, const char *str, ...@@ -220,7 +220,8 @@ static int setup_compute(const struct option *opt, const char *str,
static double period_percent(struct hist_entry *he, u64 period) static double period_percent(struct hist_entry *he, u64 period)
{ {
u64 total = he->hists->stats.total_period; u64 total = hists__total_period(he->hists);
return (period * 100.0) / total; return (period * 100.0) / total;
} }
...@@ -259,11 +260,18 @@ static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair) ...@@ -259,11 +260,18 @@ static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
static int formula_delta(struct hist_entry *he, struct hist_entry *pair, static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
char *buf, size_t size) char *buf, size_t size)
{ {
u64 he_total = he->hists->stats.total_period;
u64 pair_total = pair->hists->stats.total_period;
if (symbol_conf.filter_relative) {
he_total = he->hists->stats.total_non_filtered_period;
pair_total = pair->hists->stats.total_non_filtered_period;
}
return scnprintf(buf, size, return scnprintf(buf, size,
"(%" PRIu64 " * 100 / %" PRIu64 ") - " "(%" PRIu64 " * 100 / %" PRIu64 ") - "
"(%" PRIu64 " * 100 / %" PRIu64 ")", "(%" PRIu64 " * 100 / %" PRIu64 ")",
pair->stat.period, pair->hists->stats.total_period, pair->stat.period, pair_total,
he->stat.period, he->hists->stats.total_period); he->stat.period, he_total);
} }
static int formula_ratio(struct hist_entry *he, struct hist_entry *pair, static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
...@@ -327,15 +335,16 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused, ...@@ -327,15 +335,16 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
return -1; return -1;
} }
if (al.filtered)
return 0;
if (hists__add_entry(&evsel->hists, &al, sample->period, if (hists__add_entry(&evsel->hists, &al, sample->period,
sample->weight, sample->transaction)) { sample->weight, sample->transaction)) {
pr_warning("problem incrementing symbol period, skipping event\n"); pr_warning("problem incrementing symbol period, skipping event\n");
return -1; return -1;
} }
if (al.filtered == 0) {
evsel->hists.stats.total_non_filtered_period += sample->period;
evsel->hists.nr_non_filtered_entries++;
}
evsel->hists.stats.total_period += sample->period; evsel->hists.stats.total_period += sample->period;
return 0; return 0;
} }
...@@ -565,7 +574,9 @@ static void hists__compute_resort(struct hists *hists) ...@@ -565,7 +574,9 @@ static void hists__compute_resort(struct hists *hists)
next = rb_first(root); next = rb_first(root);
hists->nr_entries = 0; hists->nr_entries = 0;
hists->nr_non_filtered_entries = 0;
hists->stats.total_period = 0; hists->stats.total_period = 0;
hists->stats.total_non_filtered_period = 0;
hists__reset_col_len(hists); hists__reset_col_len(hists);
while (next != NULL) { while (next != NULL) {
...@@ -732,13 +743,16 @@ static const struct option options[] = { ...@@ -732,13 +743,16 @@ static const struct option options[] = {
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory", OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
"Look for files with symbols relative to this directory"), "Look for files with symbols relative to this directory"),
OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."), OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
"How to display percentage of filtered entries", parse_filter_percentage),
OPT_END() OPT_END()
}; };
static double baseline_percent(struct hist_entry *he) static double baseline_percent(struct hist_entry *he)
{ {
struct hists *hists = he->hists; u64 total = hists__total_period(he->hists);
return 100.0 * he->stat.period / hists->stats.total_period;
return 100.0 * he->stat.period / total;
} }
static int hpp__color_baseline(struct perf_hpp_fmt *fmt, static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
...@@ -1120,6 +1134,8 @@ static int data_init(int argc, const char **argv) ...@@ -1120,6 +1134,8 @@ static int data_init(int argc, const char **argv)
int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused) int cmd_diff(int argc, const char **argv, const char *prefix __maybe_unused)
{ {
perf_config(perf_default_config, NULL);
sort_order = diff__default_sort_order; sort_order = diff__default_sort_order;
argc = parse_options(argc, argv, options, diff_usage, 0); argc = parse_options(argc, argv, options, diff_usage, 0);
......
...@@ -756,11 +756,13 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -756,11 +756,13 @@ int cmd_kmem(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"), OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
OPT_END() OPT_END()
}; };
const char * const kmem_usage[] = { const char *const kmem_subcommands[] = { "record", "stat", NULL };
"perf kmem [<options>] {record|stat}", const char *kmem_usage[] = {
NULL,
NULL NULL
}; };
argc = parse_options(argc, argv, kmem_options, kmem_usage, 0); argc = parse_options_subcommand(argc, argv, kmem_options,
kmem_subcommands, kmem_usage, 0);
if (!argc) if (!argc)
usage_with_options(kmem_usage, kmem_options); usage_with_options(kmem_usage, kmem_options);
......
...@@ -961,8 +961,10 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -961,8 +961,10 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
"perf lock info [<options>]", "perf lock info [<options>]",
NULL NULL
}; };
const char * const lock_usage[] = { const char *const lock_subcommands[] = { "record", "report", "script",
"perf lock [<options>] {record|report|script|info}", "info", NULL };
const char *lock_usage[] = {
NULL,
NULL NULL
}; };
const char * const report_usage[] = { const char * const report_usage[] = {
...@@ -976,8 +978,8 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -976,8 +978,8 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
for (i = 0; i < LOCKHASH_SIZE; i++) for (i = 0; i < LOCKHASH_SIZE; i++)
INIT_LIST_HEAD(lockhash_table + i); INIT_LIST_HEAD(lockhash_table + i);
argc = parse_options(argc, argv, lock_options, lock_usage, argc = parse_options_subcommand(argc, argv, lock_options, lock_subcommands,
PARSE_OPT_STOP_AT_NON_OPTION); lock_usage, PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc) if (!argc)
usage_with_options(lock_usage, lock_options); usage_with_options(lock_usage, lock_options);
......
...@@ -21,11 +21,6 @@ struct perf_mem { ...@@ -21,11 +21,6 @@ struct perf_mem {
DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS); DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
}; };
static const char * const mem_usage[] = {
"perf mem [<options>] {record <command> |report}",
NULL
};
static int __cmd_record(int argc, const char **argv) static int __cmd_record(int argc, const char **argv)
{ {
int rec_argc, i = 0, j; int rec_argc, i = 0, j;
...@@ -220,9 +215,15 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -220,9 +215,15 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
" between columns '.' is reserved."), " between columns '.' is reserved."),
OPT_END() OPT_END()
}; };
const char *const mem_subcommands[] = { "record", "report", NULL };
const char *mem_usage[] = {
NULL,
NULL
};
argc = parse_options(argc, argv, mem_options, mem_usage, argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands,
PARSE_OPT_STOP_AT_NON_OPTION); mem_usage, PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc || !(strncmp(argv[0], "rec", 3) || mem_operation)) if (!argc || !(strncmp(argv[0], "rec", 3) || mem_operation))
usage_with_options(mem_usage, mem_options); usage_with_options(mem_usage, mem_options);
......
...@@ -123,6 +123,8 @@ static int report__add_mem_hist_entry(struct report *rep, struct addr_location * ...@@ -123,6 +123,8 @@ static int report__add_mem_hist_entry(struct report *rep, struct addr_location *
evsel->hists.stats.total_period += cost; evsel->hists.stats.total_period += cost;
hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
if (!he->filtered)
evsel->hists.stats.nr_non_filtered_samples++;
err = hist_entry__append_callchain(he, sample); err = hist_entry__append_callchain(he, sample);
out: out:
return err; return err;
...@@ -176,6 +178,8 @@ static int report__add_branch_hist_entry(struct report *rep, struct addr_locatio ...@@ -176,6 +178,8 @@ static int report__add_branch_hist_entry(struct report *rep, struct addr_locatio
evsel->hists.stats.total_period += 1; evsel->hists.stats.total_period += 1;
hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
if (!he->filtered)
evsel->hists.stats.nr_non_filtered_samples++;
} else } else
goto out; goto out;
} }
...@@ -209,6 +213,8 @@ static int report__add_hist_entry(struct report *rep, struct perf_evsel *evsel, ...@@ -209,6 +213,8 @@ static int report__add_hist_entry(struct report *rep, struct perf_evsel *evsel,
err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr); err = hist_entry__inc_addr_samples(he, evsel->idx, al->addr);
evsel->hists.stats.total_period += sample->period; evsel->hists.stats.total_period += sample->period;
if (!he->filtered)
evsel->hists.stats.nr_non_filtered_samples++;
hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
out: out:
return err; return err;
...@@ -337,6 +343,11 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report ...@@ -337,6 +343,11 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
char buf[512]; char buf[512];
size_t size = sizeof(buf); size_t size = sizeof(buf);
if (symbol_conf.filter_relative) {
nr_samples = hists->stats.nr_non_filtered_samples;
nr_events = hists->stats.total_non_filtered_period;
}
if (perf_evsel__is_group_event(evsel)) { if (perf_evsel__is_group_event(evsel)) {
struct perf_evsel *pos; struct perf_evsel *pos;
...@@ -344,8 +355,13 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report ...@@ -344,8 +355,13 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
evname = buf; evname = buf;
for_each_group_member(pos, evsel) { for_each_group_member(pos, evsel) {
nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; if (symbol_conf.filter_relative) {
nr_events += pos->hists.stats.total_period; nr_samples += pos->hists.stats.nr_non_filtered_samples;
nr_events += pos->hists.stats.total_non_filtered_period;
} else {
nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
nr_events += pos->hists.stats.total_period;
}
} }
} }
...@@ -823,6 +839,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -823,6 +839,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"), OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
OPT_CALLBACK(0, "percent-limit", &report, "percent", OPT_CALLBACK(0, "percent-limit", &report, "percent",
"Don't show entries under that percent", parse_percent_limit), "Don't show entries under that percent", parse_percent_limit),
OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
"how to display percentage of filtered entries", parse_filter_percentage),
OPT_END() OPT_END()
}; };
struct perf_data_file file = { struct perf_data_file file = {
......
...@@ -1713,8 +1713,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1713,8 +1713,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
"perf sched replay [<options>]", "perf sched replay [<options>]",
NULL NULL
}; };
const char * const sched_usage[] = { const char *const sched_subcommands[] = { "record", "latency", "map",
"perf sched [<options>] {record|latency|map|replay|script}", "replay", "script", NULL };
const char *sched_usage[] = {
NULL,
NULL NULL
}; };
struct trace_sched_handler lat_ops = { struct trace_sched_handler lat_ops = {
...@@ -1736,8 +1738,8 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1736,8 +1738,8 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
for (i = 0; i < ARRAY_SIZE(sched.curr_pid); i++) for (i = 0; i < ARRAY_SIZE(sched.curr_pid); i++)
sched.curr_pid[i] = -1; sched.curr_pid[i] = -1;
argc = parse_options(argc, argv, sched_options, sched_usage, argc = parse_options_subcommand(argc, argv, sched_options, sched_subcommands,
PARSE_OPT_STOP_AT_NON_OPTION); sched_usage, PARSE_OPT_STOP_AT_NON_OPTION);
if (!argc) if (!argc)
usage_with_options(sched_usage, sched_options); usage_with_options(sched_usage, sched_options);
......
...@@ -253,6 +253,9 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel, ...@@ -253,6 +253,9 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
return NULL; return NULL;
hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE); hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
if (!he->filtered)
evsel->hists.stats.nr_non_filtered_samples++;
return he; return he;
} }
...@@ -694,8 +697,7 @@ static void perf_event__process_sample(struct perf_tool *tool, ...@@ -694,8 +697,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
if (event->header.misc & PERF_RECORD_MISC_EXACT_IP) if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
top->exact_samples++; top->exact_samples++;
if (perf_event__preprocess_sample(event, machine, &al, sample) < 0 || if (perf_event__preprocess_sample(event, machine, &al, sample) < 0)
al.filtered)
return; return;
if (!top->kptr_restrict_warned && if (!top->kptr_restrict_warned &&
...@@ -1116,6 +1118,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused) ...@@ -1116,6 +1118,8 @@ int cmd_top(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"), OPT_STRING('u', "uid", &target->uid_str, "user", "user to profile"),
OPT_CALLBACK(0, "percent-limit", &top, "percent", OPT_CALLBACK(0, "percent-limit", &top, "percent",
"Don't show entries under that percent", parse_percent_limit), "Don't show entries under that percent", parse_percent_limit),
OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
"How to display percentage of filtered entries", parse_filter_percentage),
OPT_END() OPT_END()
}; };
const char * const top_usage[] = { const char * const top_usage[] = {
......
...@@ -121,8 +121,8 @@ __perf_main () ...@@ -121,8 +121,8 @@ __perf_main ()
elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then
evts=$($cmd list --raw-dump) evts=$($cmd list --raw-dump)
__perfcomp_colon "$evts" "$cur" __perfcomp_colon "$evts" "$cur"
# List subcommands for 'perf kvm' # List subcommands for perf commands
elif [[ $prev == "kvm" ]]; then elif [[ $prev == @(kvm|kmem|mem|lock|sched) ]]; then
subcmds=$($cmd $prev --list-cmds) subcmds=$($cmd $prev --list-cmds)
__perfcomp_colon "$subcmds" "$cur" __perfcomp_colon "$subcmds" "$cur"
# List long option names # List long option names
......
...@@ -769,12 +769,15 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser) ...@@ -769,12 +769,15 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
for (nd = browser->top; nd; nd = rb_next(nd)) { for (nd = browser->top; nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
float percent = h->stat.period * 100.0 / u64 total = hists__total_period(h->hists);
hb->hists->stats.total_period; float percent = 0.0;
if (h->filtered) if (h->filtered)
continue; continue;
if (total)
percent = h->stat.period * 100.0 / total;
if (percent < hb->min_pcnt) if (percent < hb->min_pcnt)
continue; continue;
...@@ -792,8 +795,11 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd, ...@@ -792,8 +795,11 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd,
{ {
while (nd != NULL) { while (nd != NULL) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
float percent = h->stat.period * 100.0 / u64 total = hists__total_period(hists);
hists->stats.total_period; float percent = 0.0;
if (total)
percent = h->stat.period * 100.0 / total;
if (percent < min_pcnt) if (percent < min_pcnt)
return NULL; return NULL;
...@@ -813,8 +819,11 @@ static struct rb_node *hists__filter_prev_entries(struct rb_node *nd, ...@@ -813,8 +819,11 @@ static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
{ {
while (nd != NULL) { while (nd != NULL) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
float percent = h->stat.period * 100.0 / u64 total = hists__total_period(hists);
hists->stats.total_period; float percent = 0.0;
if (total)
percent = h->stat.period * 100.0 / total;
if (!h->filtered && percent >= min_pcnt) if (!h->filtered && percent >= min_pcnt)
return nd; return nd;
...@@ -1189,6 +1198,11 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size, ...@@ -1189,6 +1198,11 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
char buf[512]; char buf[512];
size_t buflen = sizeof(buf); size_t buflen = sizeof(buf);
if (symbol_conf.filter_relative) {
nr_samples = hists->stats.nr_non_filtered_samples;
nr_events = hists->stats.total_non_filtered_period;
}
if (perf_evsel__is_group_event(evsel)) { if (perf_evsel__is_group_event(evsel)) {
struct perf_evsel *pos; struct perf_evsel *pos;
...@@ -1196,8 +1210,13 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size, ...@@ -1196,8 +1210,13 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
ev_name = buf; ev_name = buf;
for_each_group_member(pos, evsel) { for_each_group_member(pos, evsel) {
nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE]; if (symbol_conf.filter_relative) {
nr_events += pos->hists.stats.total_period; nr_samples += pos->hists.stats.nr_non_filtered_samples;
nr_events += pos->hists.stats.total_non_filtered_period;
} else {
nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
nr_events += pos->hists.stats.total_period;
}
} }
} }
...@@ -1370,6 +1389,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1370,6 +1389,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
"C Collapse all callchains\n" \ "C Collapse all callchains\n" \
"d Zoom into current DSO\n" \ "d Zoom into current DSO\n" \
"E Expand all callchains\n" \ "E Expand all callchains\n" \
"F Toggle percentage of filtered entries\n" \
/* help messages are sorted by lexical order of the hotkey */ /* help messages are sorted by lexical order of the hotkey */
const char report_help[] = HIST_BROWSER_HELP_COMMON const char report_help[] = HIST_BROWSER_HELP_COMMON
...@@ -1475,6 +1495,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events, ...@@ -1475,6 +1495,9 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
if (env->arch) if (env->arch)
tui__header_window(env); tui__header_window(env);
continue; continue;
case 'F':
symbol_conf.filter_relative ^= 1;
continue;
case K_F1: case K_F1:
case 'h': case 'h':
case '?': case '?':
......
...@@ -228,12 +228,15 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, ...@@ -228,12 +228,15 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node); struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
GtkTreeIter iter; GtkTreeIter iter;
float percent = h->stat.period * 100.0 / u64 total = hists__total_period(h->hists);
hists->stats.total_period; float percent = 0.0;
if (h->filtered) if (h->filtered)
continue; continue;
if (total)
percent = h->stat.period * 100.0 / total;
if (percent < min_pcnt) if (percent < min_pcnt)
continue; continue;
...@@ -261,12 +264,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists, ...@@ -261,12 +264,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
} }
if (symbol_conf.use_callchain && sort__has_sym) { if (symbol_conf.use_callchain && sort__has_sym) {
u64 total;
if (callchain_param.mode == CHAIN_GRAPH_REL) if (callchain_param.mode == CHAIN_GRAPH_REL)
total = h->stat.period; total = h->stat.period;
else
total = hists->stats.total_period;
perf_gtk__add_callchain(&h->sorted_chain, store, &iter, perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
sym_col, total); sym_col, total);
......
...@@ -32,10 +32,10 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, ...@@ -32,10 +32,10 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
if (fmt_percent) { if (fmt_percent) {
double percent = 0.0; double percent = 0.0;
u64 total = hists__total_period(hists);
if (hists->stats.total_period) if (total)
percent = 100.0 * get_field(he) / percent = 100.0 * get_field(he) / total;
hists->stats.total_period;
ret += hpp__call_print_fn(hpp, print_fn, fmt, percent); ret += hpp__call_print_fn(hpp, print_fn, fmt, percent);
} else } else
...@@ -50,7 +50,7 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he, ...@@ -50,7 +50,7 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
list_for_each_entry(pair, &he->pairs.head, pairs.node) { list_for_each_entry(pair, &he->pairs.head, pairs.node) {
u64 period = get_field(pair); u64 period = get_field(pair);
u64 total = pair->hists->stats.total_period; u64 total = hists__total_period(pair->hists);
if (!total) if (!total)
continue; continue;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "util.h" #include "util.h"
#include "cache.h" #include "cache.h"
#include "exec_cmd.h" #include "exec_cmd.h"
#include "util/hist.h" /* perf_hist_config */
#define MAXNAME (256) #define MAXNAME (256)
...@@ -355,6 +356,9 @@ int perf_default_config(const char *var, const char *value, ...@@ -355,6 +356,9 @@ int perf_default_config(const char *var, const char *value,
if (!prefixcmp(var, "core.")) if (!prefixcmp(var, "core."))
return perf_default_core_config(var, value); return perf_default_core_config(var, value);
if (!prefixcmp(var, "hist."))
return perf_hist_config(var, value);
/* Add other config variables here. */ /* Add other config variables here. */
return 0; return 0;
} }
......
...@@ -321,9 +321,11 @@ void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h) ...@@ -321,9 +321,11 @@ void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
{ {
if (!h->filtered) { if (!h->filtered) {
hists__calc_col_len(hists, h); hists__calc_col_len(hists, h);
++hists->nr_entries; hists->nr_non_filtered_entries++;
hists->stats.total_period += h->stat.period; hists->stats.total_non_filtered_period += h->stat.period;
} }
hists->nr_entries++;
hists->stats.total_period += h->stat.period;
} }
static u8 symbol__parent_filter(const struct symbol *parent) static u8 symbol__parent_filter(const struct symbol *parent)
...@@ -674,8 +676,9 @@ void hists__output_resort(struct hists *hists) ...@@ -674,8 +676,9 @@ void hists__output_resort(struct hists *hists)
next = rb_first(root); next = rb_first(root);
hists->entries = RB_ROOT; hists->entries = RB_ROOT;
hists->nr_entries = 0; hists->nr_non_filtered_entries = 0;
hists->stats.total_period = 0; hists->stats.total_period = 0;
hists->stats.total_non_filtered_period = 0;
hists__reset_col_len(hists); hists__reset_col_len(hists);
while (next) { while (next) {
...@@ -694,12 +697,12 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h ...@@ -694,12 +697,12 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
if (h->filtered) if (h->filtered)
return; return;
++hists->nr_entries; ++hists->nr_non_filtered_entries;
if (h->ms.unfolded) if (h->ms.unfolded)
hists->nr_entries += h->nr_rows; hists->nr_non_filtered_entries += h->nr_rows;
h->row_offset = 0; h->row_offset = 0;
hists->stats.total_period += h->stat.period; hists->stats.total_non_filtered_period += h->stat.period;
hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->stat.nr_events; hists->stats.nr_non_filtered_samples += h->stat.nr_events;
hists__calc_col_len(hists, h); hists__calc_col_len(hists, h);
} }
...@@ -721,8 +724,9 @@ void hists__filter_by_dso(struct hists *hists) ...@@ -721,8 +724,9 @@ void hists__filter_by_dso(struct hists *hists)
{ {
struct rb_node *nd; struct rb_node *nd;
hists->nr_entries = hists->stats.total_period = 0; hists->nr_non_filtered_entries = 0;
hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; hists->stats.total_non_filtered_period = 0;
hists->stats.nr_non_filtered_samples = 0;
hists__reset_col_len(hists); hists__reset_col_len(hists);
for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
...@@ -754,8 +758,9 @@ void hists__filter_by_thread(struct hists *hists) ...@@ -754,8 +758,9 @@ void hists__filter_by_thread(struct hists *hists)
{ {
struct rb_node *nd; struct rb_node *nd;
hists->nr_entries = hists->stats.total_period = 0; hists->nr_non_filtered_entries = 0;
hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; hists->stats.total_non_filtered_period = 0;
hists->stats.nr_non_filtered_samples = 0;
hists__reset_col_len(hists); hists__reset_col_len(hists);
for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
...@@ -785,8 +790,9 @@ void hists__filter_by_symbol(struct hists *hists) ...@@ -785,8 +790,9 @@ void hists__filter_by_symbol(struct hists *hists)
{ {
struct rb_node *nd; struct rb_node *nd;
hists->nr_entries = hists->stats.total_period = 0; hists->nr_non_filtered_entries = 0;
hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0; hists->stats.total_non_filtered_period = 0;
hists->stats.nr_non_filtered_samples = 0;
hists__reset_col_len(hists); hists__reset_col_len(hists);
for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) { for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
...@@ -931,3 +937,30 @@ int hists__link(struct hists *leader, struct hists *other) ...@@ -931,3 +937,30 @@ int hists__link(struct hists *leader, struct hists *other)
return 0; return 0;
} }
u64 hists__total_period(struct hists *hists)
{
return symbol_conf.filter_relative ? hists->stats.total_non_filtered_period :
hists->stats.total_period;
}
int parse_filter_percentage(const struct option *opt __maybe_unused,
const char *arg, int unset __maybe_unused)
{
if (!strcmp(arg, "relative"))
symbol_conf.filter_relative = true;
else if (!strcmp(arg, "absolute"))
symbol_conf.filter_relative = false;
else
return -1;
return 0;
}
int perf_hist_config(const char *var, const char *value)
{
if (!strcmp(var, "hist.percentage"))
return parse_filter_percentage(NULL, value, 0);
return 0;
}
...@@ -37,9 +37,11 @@ enum hist_filter { ...@@ -37,9 +37,11 @@ enum hist_filter {
*/ */
struct events_stats { struct events_stats {
u64 total_period; u64 total_period;
u64 total_non_filtered_period;
u64 total_lost; u64 total_lost;
u64 total_invalid_chains; u64 total_invalid_chains;
u32 nr_events[PERF_RECORD_HEADER_MAX]; u32 nr_events[PERF_RECORD_HEADER_MAX];
u32 nr_non_filtered_samples;
u32 nr_lost_warned; u32 nr_lost_warned;
u32 nr_unknown_events; u32 nr_unknown_events;
u32 nr_invalid_chains; u32 nr_invalid_chains;
...@@ -83,6 +85,7 @@ struct hists { ...@@ -83,6 +85,7 @@ struct hists {
struct rb_root entries; struct rb_root entries;
struct rb_root entries_collapsed; struct rb_root entries_collapsed;
u64 nr_entries; u64 nr_entries;
u64 nr_non_filtered_entries;
const struct thread *thread_filter; const struct thread *thread_filter;
const struct dso *dso_filter; const struct dso *dso_filter;
const char *uid_filter_str; const char *uid_filter_str;
...@@ -112,6 +115,7 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog); ...@@ -112,6 +115,7 @@ void hists__collapse_resort(struct hists *hists, struct ui_progress *prog);
void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel); void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel);
void hists__output_recalc_col_len(struct hists *hists, int max_rows); void hists__output_recalc_col_len(struct hists *hists, int max_rows);
u64 hists__total_period(struct hists *hists);
void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h); void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h);
void hists__inc_nr_events(struct hists *hists, u32 type); void hists__inc_nr_events(struct hists *hists, u32 type);
void events_stats__inc(struct events_stats *stats, u32 type); void events_stats__inc(struct events_stats *stats, u32 type);
...@@ -250,4 +254,10 @@ static inline int script_browse(const char *script_opt __maybe_unused) ...@@ -250,4 +254,10 @@ static inline int script_browse(const char *script_opt __maybe_unused)
#endif #endif
unsigned int hists__sort_list_width(struct hists *hists); unsigned int hists__sort_list_width(struct hists *hists);
struct option;
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);
#endif /* __PERF_HIST_H */ #endif /* __PERF_HIST_H */
...@@ -115,7 +115,8 @@ struct symbol_conf { ...@@ -115,7 +115,8 @@ struct symbol_conf {
annotate_asm_raw, annotate_asm_raw,
annotate_src, annotate_src,
event_group, event_group,
demangle; demangle,
filter_relative;
const char *vmlinux_name, const char *vmlinux_name,
*kallsyms_name, *kallsyms_name,
*source_prefix, *source_prefix,
......
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