--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
-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.
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
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;
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;
+ }
}
}
return 0;
}
+static int
+parse_percentage(const struct option *opt __maybe_unused, const char *str,
+ int unset __maybe_unused)
+{
+ if (!strcmp(str, "relative"))
+ symbol_conf.filter_relative = true;
+ else if (!strcmp(str, "absolute"))
+ symbol_conf.filter_relative = false;
+ else
+ return -1;
+
+ return 0;
+}
+
int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
{
struct perf_session *session;
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_percentage),
OPT_END()
};
struct perf_data_file file = {
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;
{
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;
{
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;
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;
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;
+ }
}
}
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;
}
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);
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
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;
{
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)
next = rb_first(root);
hists->entries = RB_ROOT;
- hists->nr_entries = hists->nr_non_filtered_entries = 0;
- hists->stats.total_period = hists->stats.total_non_filtered_period = 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) {
if (h->filtered)
return;
- ++hists->nr_entries;
++hists->nr_non_filtered_entries;
- if (h->ms.unfolded) {
- hists->nr_entries += h->nr_rows;
+ if (h->ms.unfolded)
hists->nr_non_filtered_entries += h->nr_rows;
- }
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);
{
struct rb_node *nd;
- hists->nr_entries = hists->stats.total_period = 0;
- hists->nr_non_filtered_entries = hists->stats.total_non_filtered_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);
{
struct rb_node *nd;
- hists->nr_entries = hists->stats.total_period = 0;
- hists->nr_non_filtered_entries = hists->stats.total_non_filtered_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);
{
struct rb_node *nd;
- hists->nr_entries = hists->stats.total_period = 0;
- hists->nr_non_filtered_entries = hists->stats.total_non_filtered_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);
return 0;
}
+
+u64 hists__total_period(struct hists *hists)
+{
+ return symbol_conf.filter_relative ? hists->stats.total_non_filtered_period :
+ hists->stats.total_period;
+}
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);
.try_vmlinux_path = true,
.annotate_src = true,
.demangle = true,
+ .filter_relative = true,
.symfs = "",
};
annotate_asm_raw,
annotate_src,
event_group,
- demangle;
+ demangle,
+ filter_relative;
const char *vmlinux_name,
*kallsyms_name,
*source_prefix,