perf/core improvements and fixes:
User visible: . Add --percentage option to control absolute/relative percentage output (Namhyung Kim) Developer stuff: . Add --list-cmds to 'kmem', 'mem', 'lock' and 'sched', for use by completion scripts (Ramkumar Ramachandra) Signed-off-by: Jiri Olsa <jolsa@redhat.com> -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJTTsj7AAoJEPZqUSBWB3s98OEP/AzBJviyJSRqf/DNxMZpnuyT E1Pd9R8IUT50sWGklEYZcjeCG8JPF46sHcuf5v/tXCwni4u0muJ2imcOJzBKf4it XVpXA+E7bNt/oAr+8RVcZ0mhusX2DqafCZOVRTnuUv5y5JG7cWd9fC8qW2Hu6oYe SOfjNRpwi9tV6aCkJUMbJT6SaW+rMGSxHLxv77KK/uP50Ekd/H06TyVspsJRfFeB rckEIm8p3svQWX7EAHs09p7BxAarTbrK0TWzgfL3YEnCee/y0y9xxN32Pdc8fGj5 bKx6uRe5HWDcZZZvDIIDQeZLECwBu4xJvQPeRE9AeDs8NgXyvnNvljED+RSXcQ/F zxnxYmviZSz/15B8fQ3TWIv+fd1rsc7hnbnmY1U+vPWdRgsc0spTFKZiKtDkLIBq jZI+vwhgznDCjajBdKTAVQj6lErupP9ML6HIRcQPWu1YHoDbPiM+ZZ0xskIcsOuE AfMAu5reYXW4bPGIA80AEEKLRjTjxcYlNadyQOHYZO/fE+SPs7iW+c/sm/+boN+r dWX8NeK6Nfz45wunBIxvXaCM/MnBvTuH657fZQlKuf43radnrduZRjf/Q+yDUEfQ VovatgZlK7PRJiIfBUfYfG+ov1cr0F9qJKBYyC8fIrNtWNsvfIwFd3ubkOQBW/qG Q0PYdJPNL0furiI0VWO0 =cjaT -----END PGP SIGNATURE----- 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: Jiri Olsa <jolsa@redhat.com> Signed-off-by: Ingo Molnar <mingo@kernel.org>
This commit is contained in:
commit
b3d5fc3c29
18 changed files with 230 additions and 76 deletions
|
@ -33,17 +33,20 @@ OPTIONS
|
|||
-d::
|
||||
--dsos=::
|
||||
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::
|
||||
--comms=::
|
||||
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::
|
||||
--symbols=::
|
||||
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::
|
||||
--sort=::
|
||||
|
@ -89,6 +92,14 @@ OPTIONS
|
|||
--order::
|
||||
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
|
||||
----------
|
||||
The comparison is governed by the baseline file. The baseline perf.data
|
||||
|
@ -157,6 +168,10 @@ with:
|
|||
- period_percent being the % of the hist entry period value within
|
||||
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
|
||||
~~~~~
|
||||
If specified the 'Ratio' column is displayed with value 'r' computed as:
|
||||
|
|
|
@ -25,10 +25,6 @@ OPTIONS
|
|||
--verbose::
|
||||
Be more verbose. (show symbol address, etc)
|
||||
|
||||
-d::
|
||||
--dsos=::
|
||||
Only consider symbols in these dsos. CSV that understands
|
||||
file://filename entries.
|
||||
-n::
|
||||
--show-nr-samples::
|
||||
Show the number of samples for each symbol
|
||||
|
@ -42,11 +38,18 @@ OPTIONS
|
|||
-c::
|
||||
--comms=::
|
||||
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::
|
||||
--symbols=::
|
||||
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=::
|
||||
Only show symbols that match (partially) with this filter.
|
||||
|
@ -237,6 +240,15 @@ OPTIONS
|
|||
Do not show entries which have an overhead under that percent.
|
||||
(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::
|
||||
Show header information in the perf.data file. This includes
|
||||
various information like hostname, OS and perf version, cpu/mem
|
||||
|
|
|
@ -123,13 +123,16 @@ Default is to monitor all CPUS.
|
|||
Show a column with the sum of periods.
|
||||
|
||||
--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::
|
||||
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::
|
||||
Only consider these symbols.
|
||||
Only consider these symbols. This option will affect the
|
||||
percentage of the overhead column. See --percentage for more info.
|
||||
|
||||
-M::
|
||||
--disassembler-style=:: Set disassembler style for objdump.
|
||||
|
@ -165,6 +168,15 @@ Default is to monitor all CPUS.
|
|||
Do not show entries which have an overhead under that percent.
|
||||
(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
|
||||
--------------------------
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
u64 total = he->hists->stats.total_period;
|
||||
u64 total = hists__total_period(he->hists);
|
||||
|
||||
return (period * 100.0) / total;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
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,
|
||||
"(%" PRIu64 " * 100 / %" PRIu64 ") - "
|
||||
"(%" PRIu64 " * 100 / %" PRIu64 ")",
|
||||
pair->stat.period, pair->hists->stats.total_period,
|
||||
he->stat.period, he->hists->stats.total_period);
|
||||
pair->stat.period, pair_total,
|
||||
he->stat.period, he_total);
|
||||
}
|
||||
|
||||
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,
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (al.filtered)
|
||||
return 0;
|
||||
|
||||
if (hists__add_entry(&evsel->hists, &al, sample->period,
|
||||
sample->weight, sample->transaction)) {
|
||||
pr_warning("problem incrementing symbol period, skipping event\n");
|
||||
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;
|
||||
return 0;
|
||||
}
|
||||
|
@ -565,7 +574,9 @@ static void hists__compute_resort(struct hists *hists)
|
|||
next = rb_first(root);
|
||||
|
||||
hists->nr_entries = 0;
|
||||
hists->nr_non_filtered_entries = 0;
|
||||
hists->stats.total_period = 0;
|
||||
hists->stats.total_non_filtered_period = 0;
|
||||
hists__reset_col_len(hists);
|
||||
|
||||
while (next != NULL) {
|
||||
|
@ -732,13 +743,16 @@ static const struct option options[] = {
|
|||
OPT_STRING(0, "symfs", &symbol_conf.symfs, "directory",
|
||||
"Look for files with symbols relative to this directory"),
|
||||
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()
|
||||
};
|
||||
|
||||
static double baseline_percent(struct hist_entry *he)
|
||||
{
|
||||
struct hists *hists = he->hists;
|
||||
return 100.0 * he->stat.period / hists->stats.total_period;
|
||||
u64 total = hists__total_period(he->hists);
|
||||
|
||||
return 100.0 * he->stat.period / total;
|
||||
}
|
||||
|
||||
static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
|
||||
|
@ -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)
|
||||
{
|
||||
perf_config(perf_default_config, NULL);
|
||||
|
||||
sort_order = diff__default_sort_order;
|
||||
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)
|
|||
OPT_BOOLEAN(0, "raw-ip", &raw_ip, "show raw ip instead of symbol"),
|
||||
OPT_END()
|
||||
};
|
||||
const char * const kmem_usage[] = {
|
||||
"perf kmem [<options>] {record|stat}",
|
||||
const char *const kmem_subcommands[] = { "record", "stat", NULL };
|
||||
const char *kmem_usage[] = {
|
||||
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)
|
||||
usage_with_options(kmem_usage, kmem_options);
|
||||
|
|
|
@ -961,8 +961,10 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
"perf lock info [<options>]",
|
||||
NULL
|
||||
};
|
||||
const char * const lock_usage[] = {
|
||||
"perf lock [<options>] {record|report|script|info}",
|
||||
const char *const lock_subcommands[] = { "record", "report", "script",
|
||||
"info", NULL };
|
||||
const char *lock_usage[] = {
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
const char * const report_usage[] = {
|
||||
|
@ -976,8 +978,8 @@ int cmd_lock(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
for (i = 0; i < LOCKHASH_SIZE; i++)
|
||||
INIT_LIST_HEAD(lockhash_table + i);
|
||||
|
||||
argc = parse_options(argc, argv, lock_options, lock_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
argc = parse_options_subcommand(argc, argv, lock_options, lock_subcommands,
|
||||
lock_usage, PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
if (!argc)
|
||||
usage_with_options(lock_usage, lock_options);
|
||||
|
||||
|
|
|
@ -21,11 +21,6 @@ struct perf_mem {
|
|||
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)
|
||||
{
|
||||
int rec_argc, i = 0, j;
|
||||
|
@ -220,9 +215,15 @@ int cmd_mem(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
" between columns '.' is reserved."),
|
||||
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,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
|
||||
argc = parse_options_subcommand(argc, argv, mem_options, mem_subcommands,
|
||||
mem_usage, PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
|
||||
if (!argc || !(strncmp(argv[0], "rec", 3) || mem_operation))
|
||||
usage_with_options(mem_usage, mem_options);
|
||||
|
|
|
@ -123,6 +123,8 @@ static int report__add_mem_hist_entry(struct report *rep, struct addr_location *
|
|||
|
||||
evsel->hists.stats.total_period += cost;
|
||||
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);
|
||||
out:
|
||||
return err;
|
||||
|
@ -176,6 +178,8 @@ static int report__add_branch_hist_entry(struct report *rep, struct addr_locatio
|
|||
|
||||
evsel->hists.stats.total_period += 1;
|
||||
hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
|
||||
if (!he->filtered)
|
||||
evsel->hists.stats.nr_non_filtered_samples++;
|
||||
} else
|
||||
goto out;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
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);
|
||||
out:
|
||||
return err;
|
||||
|
@ -337,6 +343,11 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
|
|||
char buf[512];
|
||||
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)) {
|
||||
struct perf_evsel *pos;
|
||||
|
||||
|
@ -344,8 +355,13 @@ static size_t hists__fprintf_nr_sample_events(struct hists *hists, struct report
|
|||
evname = buf;
|
||||
|
||||
for_each_group_member(pos, evsel) {
|
||||
nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
nr_events += pos->hists.stats.total_period;
|
||||
if (symbol_conf.filter_relative) {
|
||||
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)
|
|||
OPT_BOOLEAN(0, "mem-mode", &report.mem_mode, "mem access profile"),
|
||||
OPT_CALLBACK(0, "percent-limit", &report, "percent",
|
||||
"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()
|
||||
};
|
||||
struct perf_data_file file = {
|
||||
|
|
|
@ -1713,8 +1713,10 @@ int cmd_sched(int argc, const char **argv, const char *prefix __maybe_unused)
|
|||
"perf sched replay [<options>]",
|
||||
NULL
|
||||
};
|
||||
const char * const sched_usage[] = {
|
||||
"perf sched [<options>] {record|latency|map|replay|script}",
|
||||
const char *const sched_subcommands[] = { "record", "latency", "map",
|
||||
"replay", "script", NULL };
|
||||
const char *sched_usage[] = {
|
||||
NULL,
|
||||
NULL
|
||||
};
|
||||
struct trace_sched_handler lat_ops = {
|
||||
|
@ -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++)
|
||||
sched.curr_pid[i] = -1;
|
||||
|
||||
argc = parse_options(argc, argv, sched_options, sched_usage,
|
||||
PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
argc = parse_options_subcommand(argc, argv, sched_options, sched_subcommands,
|
||||
sched_usage, PARSE_OPT_STOP_AT_NON_OPTION);
|
||||
if (!argc)
|
||||
usage_with_options(sched_usage, sched_options);
|
||||
|
||||
|
|
|
@ -253,6 +253,9 @@ static struct hist_entry *perf_evsel__add_hist_entry(struct perf_evsel *evsel,
|
|||
return NULL;
|
||||
|
||||
hists__inc_nr_events(&evsel->hists, PERF_RECORD_SAMPLE);
|
||||
if (!he->filtered)
|
||||
evsel->hists.stats.nr_non_filtered_samples++;
|
||||
|
||||
return he;
|
||||
}
|
||||
|
||||
|
@ -694,8 +697,7 @@ static void perf_event__process_sample(struct perf_tool *tool,
|
|||
if (event->header.misc & PERF_RECORD_MISC_EXACT_IP)
|
||||
top->exact_samples++;
|
||||
|
||||
if (perf_event__preprocess_sample(event, machine, &al, sample) < 0 ||
|
||||
al.filtered)
|
||||
if (perf_event__preprocess_sample(event, machine, &al, sample) < 0)
|
||||
return;
|
||||
|
||||
if (!top->kptr_restrict_warned &&
|
||||
|
@ -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_CALLBACK(0, "percent-limit", &top, "percent",
|
||||
"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()
|
||||
};
|
||||
const char * const top_usage[] = {
|
||||
|
|
|
@ -121,8 +121,8 @@ __perf_main ()
|
|||
elif [[ $prev == "-e" && "${words[1]}" == @(record|stat|top) ]]; then
|
||||
evts=$($cmd list --raw-dump)
|
||||
__perfcomp_colon "$evts" "$cur"
|
||||
# List subcommands for 'perf kvm'
|
||||
elif [[ $prev == "kvm" ]]; then
|
||||
# List subcommands for perf commands
|
||||
elif [[ $prev == @(kvm|kmem|mem|lock|sched) ]]; then
|
||||
subcmds=$($cmd $prev --list-cmds)
|
||||
__perfcomp_colon "$subcmds" "$cur"
|
||||
# List long option names
|
||||
|
|
|
@ -769,12 +769,15 @@ static unsigned int hist_browser__refresh(struct ui_browser *browser)
|
|||
|
||||
for (nd = browser->top; nd; nd = rb_next(nd)) {
|
||||
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
|
||||
float percent = h->stat.period * 100.0 /
|
||||
hb->hists->stats.total_period;
|
||||
u64 total = hists__total_period(h->hists);
|
||||
float percent = 0.0;
|
||||
|
||||
if (h->filtered)
|
||||
continue;
|
||||
|
||||
if (total)
|
||||
percent = h->stat.period * 100.0 / total;
|
||||
|
||||
if (percent < hb->min_pcnt)
|
||||
continue;
|
||||
|
||||
|
@ -792,8 +795,11 @@ static struct rb_node *hists__filter_entries(struct rb_node *nd,
|
|||
{
|
||||
while (nd != NULL) {
|
||||
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
|
||||
float percent = h->stat.period * 100.0 /
|
||||
hists->stats.total_period;
|
||||
u64 total = hists__total_period(hists);
|
||||
float percent = 0.0;
|
||||
|
||||
if (total)
|
||||
percent = h->stat.period * 100.0 / total;
|
||||
|
||||
if (percent < min_pcnt)
|
||||
return NULL;
|
||||
|
@ -813,8 +819,11 @@ static struct rb_node *hists__filter_prev_entries(struct rb_node *nd,
|
|||
{
|
||||
while (nd != NULL) {
|
||||
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
|
||||
float percent = h->stat.period * 100.0 /
|
||||
hists->stats.total_period;
|
||||
u64 total = hists__total_period(hists);
|
||||
float percent = 0.0;
|
||||
|
||||
if (total)
|
||||
percent = h->stat.period * 100.0 / total;
|
||||
|
||||
if (!h->filtered && percent >= min_pcnt)
|
||||
return nd;
|
||||
|
@ -1189,6 +1198,11 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
|
|||
char buf[512];
|
||||
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)) {
|
||||
struct perf_evsel *pos;
|
||||
|
||||
|
@ -1196,8 +1210,13 @@ static int hists__browser_title(struct hists *hists, char *bf, size_t size,
|
|||
ev_name = buf;
|
||||
|
||||
for_each_group_member(pos, evsel) {
|
||||
nr_samples += pos->hists.stats.nr_events[PERF_RECORD_SAMPLE];
|
||||
nr_events += pos->hists.stats.total_period;
|
||||
if (symbol_conf.filter_relative) {
|
||||
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,
|
|||
"C Collapse all callchains\n" \
|
||||
"d Zoom into current DSO\n" \
|
||||
"E Expand all callchains\n" \
|
||||
"F Toggle percentage of filtered entries\n" \
|
||||
|
||||
/* help messages are sorted by lexical order of the hotkey */
|
||||
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,
|
|||
if (env->arch)
|
||||
tui__header_window(env);
|
||||
continue;
|
||||
case 'F':
|
||||
symbol_conf.filter_relative ^= 1;
|
||||
continue;
|
||||
case K_F1:
|
||||
case 'h':
|
||||
case '?':
|
||||
|
|
|
@ -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)) {
|
||||
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
|
||||
GtkTreeIter iter;
|
||||
float percent = h->stat.period * 100.0 /
|
||||
hists->stats.total_period;
|
||||
u64 total = hists__total_period(h->hists);
|
||||
float percent = 0.0;
|
||||
|
||||
if (h->filtered)
|
||||
continue;
|
||||
|
||||
if (total)
|
||||
percent = h->stat.period * 100.0 / total;
|
||||
|
||||
if (percent < min_pcnt)
|
||||
continue;
|
||||
|
||||
|
@ -261,12 +264,8 @@ static void perf_gtk__show_hists(GtkWidget *window, struct hists *hists,
|
|||
}
|
||||
|
||||
if (symbol_conf.use_callchain && sort__has_sym) {
|
||||
u64 total;
|
||||
|
||||
if (callchain_param.mode == CHAIN_GRAPH_REL)
|
||||
total = h->stat.period;
|
||||
else
|
||||
total = hists->stats.total_period;
|
||||
|
||||
perf_gtk__add_callchain(&h->sorted_chain, store, &iter,
|
||||
sym_col, total);
|
||||
|
|
|
@ -32,10 +32,10 @@ int __hpp__fmt(struct perf_hpp *hpp, struct hist_entry *he,
|
|||
|
||||
if (fmt_percent) {
|
||||
double percent = 0.0;
|
||||
u64 total = hists__total_period(hists);
|
||||
|
||||
if (hists->stats.total_period)
|
||||
percent = 100.0 * get_field(he) /
|
||||
hists->stats.total_period;
|
||||
if (total)
|
||||
percent = 100.0 * get_field(he) / total;
|
||||
|
||||
ret += hpp__call_print_fn(hpp, print_fn, fmt, percent);
|
||||
} else
|
||||
|
@ -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) {
|
||||
u64 period = get_field(pair);
|
||||
u64 total = pair->hists->stats.total_period;
|
||||
u64 total = hists__total_period(pair->hists);
|
||||
|
||||
if (!total)
|
||||
continue;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "util.h"
|
||||
#include "cache.h"
|
||||
#include "exec_cmd.h"
|
||||
#include "util/hist.h" /* perf_hist_config */
|
||||
|
||||
#define MAXNAME (256)
|
||||
|
||||
|
@ -355,6 +356,9 @@ int perf_default_config(const char *var, const char *value,
|
|||
if (!prefixcmp(var, "core."))
|
||||
return perf_default_core_config(var, value);
|
||||
|
||||
if (!prefixcmp(var, "hist."))
|
||||
return perf_hist_config(var, value);
|
||||
|
||||
/* Add other config variables here. */
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -321,9 +321,11 @@ void hists__inc_nr_entries(struct hists *hists, struct hist_entry *h)
|
|||
{
|
||||
if (!h->filtered) {
|
||||
hists__calc_col_len(hists, h);
|
||||
++hists->nr_entries;
|
||||
hists->stats.total_period += h->stat.period;
|
||||
hists->nr_non_filtered_entries++;
|
||||
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)
|
||||
|
@ -674,8 +676,9 @@ void hists__output_resort(struct hists *hists)
|
|||
next = rb_first(root);
|
||||
hists->entries = RB_ROOT;
|
||||
|
||||
hists->nr_entries = 0;
|
||||
hists->nr_non_filtered_entries = 0;
|
||||
hists->stats.total_period = 0;
|
||||
hists->stats.total_non_filtered_period = 0;
|
||||
hists__reset_col_len(hists);
|
||||
|
||||
while (next) {
|
||||
|
@ -694,12 +697,12 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
|
|||
if (h->filtered)
|
||||
return;
|
||||
|
||||
++hists->nr_entries;
|
||||
++hists->nr_non_filtered_entries;
|
||||
if (h->ms.unfolded)
|
||||
hists->nr_entries += h->nr_rows;
|
||||
hists->nr_non_filtered_entries += h->nr_rows;
|
||||
h->row_offset = 0;
|
||||
hists->stats.total_period += h->stat.period;
|
||||
hists->stats.nr_events[PERF_RECORD_SAMPLE] += h->stat.nr_events;
|
||||
hists->stats.total_non_filtered_period += h->stat.period;
|
||||
hists->stats.nr_non_filtered_samples += h->stat.nr_events;
|
||||
|
||||
hists__calc_col_len(hists, h);
|
||||
}
|
||||
|
@ -721,8 +724,9 @@ void hists__filter_by_dso(struct hists *hists)
|
|||
{
|
||||
struct rb_node *nd;
|
||||
|
||||
hists->nr_entries = hists->stats.total_period = 0;
|
||||
hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
|
||||
hists->nr_non_filtered_entries = 0;
|
||||
hists->stats.total_non_filtered_period = 0;
|
||||
hists->stats.nr_non_filtered_samples = 0;
|
||||
hists__reset_col_len(hists);
|
||||
|
||||
for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
|
||||
|
@ -754,8 +758,9 @@ void hists__filter_by_thread(struct hists *hists)
|
|||
{
|
||||
struct rb_node *nd;
|
||||
|
||||
hists->nr_entries = hists->stats.total_period = 0;
|
||||
hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
|
||||
hists->nr_non_filtered_entries = 0;
|
||||
hists->stats.total_non_filtered_period = 0;
|
||||
hists->stats.nr_non_filtered_samples = 0;
|
||||
hists__reset_col_len(hists);
|
||||
|
||||
for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
|
||||
|
@ -785,8 +790,9 @@ void hists__filter_by_symbol(struct hists *hists)
|
|||
{
|
||||
struct rb_node *nd;
|
||||
|
||||
hists->nr_entries = hists->stats.total_period = 0;
|
||||
hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
|
||||
hists->nr_non_filtered_entries = 0;
|
||||
hists->stats.total_non_filtered_period = 0;
|
||||
hists->stats.nr_non_filtered_samples = 0;
|
||||
hists__reset_col_len(hists);
|
||||
|
||||
for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
|
||||
|
@ -931,3 +937,30 @@ int hists__link(struct hists *leader, struct hists *other)
|
|||
|
||||
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 {
|
|||
*/
|
||||
struct events_stats {
|
||||
u64 total_period;
|
||||
u64 total_non_filtered_period;
|
||||
u64 total_lost;
|
||||
u64 total_invalid_chains;
|
||||
u32 nr_events[PERF_RECORD_HEADER_MAX];
|
||||
u32 nr_non_filtered_samples;
|
||||
u32 nr_lost_warned;
|
||||
u32 nr_unknown_events;
|
||||
u32 nr_invalid_chains;
|
||||
|
@ -83,6 +85,7 @@ struct hists {
|
|||
struct rb_root entries;
|
||||
struct rb_root entries_collapsed;
|
||||
u64 nr_entries;
|
||||
u64 nr_non_filtered_entries;
|
||||
const struct thread *thread_filter;
|
||||
const struct dso *dso_filter;
|
||||
const char *uid_filter_str;
|
||||
|
@ -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__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_events(struct hists *hists, 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)
|
|||
#endif
|
||||
|
||||
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 */
|
||||
|
|
|
@ -115,7 +115,8 @@ struct symbol_conf {
|
|||
annotate_asm_raw,
|
||||
annotate_src,
|
||||
event_group,
|
||||
demangle;
|
||||
demangle,
|
||||
filter_relative;
|
||||
const char *vmlinux_name,
|
||||
*kallsyms_name,
|
||||
*source_prefix,
|
||||
|
|
Loading…
Reference in a new issue