Commit 9aa09230 authored by Ian Rogers's avatar Ian Rogers Committed by Arnaldo Carvalho de Melo

perf metrics: Support all tool events

Previously duration_time was hard coded, which was ok until commit
b03b89b3 ("perf stat: Add user_time and system_time events")
added additional tool events. Do for all tool events what was previously
done just for duration_time.
Signed-off-by: default avatarIan Rogers <irogers@google.com>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Florian Fischer <florian.fischer@muhq.space>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: John Garry <john.garry@huawei.com>
Cc: Kim Phillips <kim.phillips@amd.com>
Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Riccardo Mancini <rickyman7@gmail.com>
Cc: Shunsuke Nakamura <nakamura.shun@fujitsu.com>
Cc: Stephane Eranian <eranian@google.com>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Link: https://lore.kernel.org/r/20220507053410.3798748-5-irogers@google.comSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 79932d16
...@@ -728,22 +728,23 @@ static int metricgroup__build_event_string(struct strbuf *events, ...@@ -728,22 +728,23 @@ static int metricgroup__build_event_string(struct strbuf *events,
{ {
struct hashmap_entry *cur; struct hashmap_entry *cur;
size_t bkt; size_t bkt;
bool no_group = true, has_duration = false; bool no_group = true, has_tool_events = false;
bool tool_events[PERF_TOOL_MAX] = {false};
int ret = 0; int ret = 0;
#define RETURN_IF_NON_ZERO(x) do { if (x) return x; } while (0) #define RETURN_IF_NON_ZERO(x) do { if (x) return x; } while (0)
hashmap__for_each_entry(ctx->ids, cur, bkt) { hashmap__for_each_entry(ctx->ids, cur, bkt) {
const char *sep, *rsep, *id = cur->key; const char *sep, *rsep, *id = cur->key;
enum perf_tool_event ev;
pr_debug("found event %s\n", id); pr_debug("found event %s\n", id);
/*
* Duration time maps to a software event and can make /* Always move tool events outside of the group. */
* groups not count. Always use it outside a ev = perf_tool_event__from_str(id);
* group. if (ev != PERF_TOOL_NONE) {
*/ has_tool_events = true;
if (!strcmp(id, "duration_time")) { tool_events[ev] = true;
has_duration = true;
continue; continue;
} }
/* Separate events with commas and open the group if necessary. */ /* Separate events with commas and open the group if necessary. */
...@@ -802,16 +803,25 @@ static int metricgroup__build_event_string(struct strbuf *events, ...@@ -802,16 +803,25 @@ static int metricgroup__build_event_string(struct strbuf *events,
RETURN_IF_NON_ZERO(ret); RETURN_IF_NON_ZERO(ret);
} }
} }
if (has_duration) { if (!no_group && !has_constraint) {
if (no_group) {
/* Strange case of a metric of just duration_time. */
ret = strbuf_addf(events, "duration_time");
} else if (!has_constraint)
ret = strbuf_addf(events, "}:W,duration_time");
else
ret = strbuf_addf(events, ",duration_time");
} else if (!no_group && !has_constraint)
ret = strbuf_addf(events, "}:W"); ret = strbuf_addf(events, "}:W");
RETURN_IF_NON_ZERO(ret);
}
if (has_tool_events) {
int i;
perf_tool_event__for_each_event(i) {
if (tool_events[i]) {
if (!no_group) {
ret = strbuf_addch(events, ',');
RETURN_IF_NON_ZERO(ret);
}
no_group = false;
ret = strbuf_addstr(events, perf_tool_event__to_str(i));
RETURN_IF_NON_ZERO(ret);
}
}
}
return ret; return ret;
#undef RETURN_IF_NON_ZERO #undef RETURN_IF_NON_ZERO
...@@ -1117,7 +1127,7 @@ static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe, ...@@ -1117,7 +1127,7 @@ static int metricgroup__add_metric_sys_event_iter(const struct pmu_event *pe,
/** /**
* metric_list_cmp - list_sort comparator that sorts metrics with more events to * metric_list_cmp - list_sort comparator that sorts metrics with more events to
* the front. duration_time is excluded from the count. * the front. tool events are excluded from the count.
*/ */
static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l, static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l,
const struct list_head *r) const struct list_head *r)
...@@ -1125,15 +1135,19 @@ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l, ...@@ -1125,15 +1135,19 @@ static int metric_list_cmp(void *priv __maybe_unused, const struct list_head *l,
const struct metric *left = container_of(l, struct metric, nd); const struct metric *left = container_of(l, struct metric, nd);
const struct metric *right = container_of(r, struct metric, nd); const struct metric *right = container_of(r, struct metric, nd);
struct expr_id_data *data; struct expr_id_data *data;
int left_count, right_count; int i, left_count, right_count;
left_count = hashmap__size(left->pctx->ids); left_count = hashmap__size(left->pctx->ids);
if (!expr__get_id(left->pctx, "duration_time", &data)) perf_tool_event__for_each_event(i) {
if (!expr__get_id(left->pctx, perf_tool_event__to_str(i), &data))
left_count--; left_count--;
}
right_count = hashmap__size(right->pctx->ids); right_count = hashmap__size(right->pctx->ids);
if (!expr__get_id(right->pctx, "duration_time", &data)) perf_tool_event__for_each_event(i) {
if (!expr__get_id(right->pctx, perf_tool_event__to_str(i), &data))
right_count--; right_count--;
}
return right_count - left_count; return right_count - left_count;
} }
...@@ -1331,27 +1345,28 @@ static int parse_ids(bool metric_no_merge, struct perf_pmu *fake_pmu, ...@@ -1331,27 +1345,28 @@ static int parse_ids(bool metric_no_merge, struct perf_pmu *fake_pmu,
*out_evlist = NULL; *out_evlist = NULL;
if (!metric_no_merge || hashmap__size(ids->ids) == 0) { if (!metric_no_merge || hashmap__size(ids->ids) == 0) {
char *tmp; int i;
/* /*
* We may fail to share events between metrics because * We may fail to share events between metrics because a tool
* duration_time isn't present in one metric. For example, a * event isn't present in one metric. For example, a ratio of
* ratio of cache misses doesn't need duration_time but the same * cache misses doesn't need duration_time but the same events
* events may be used for a misses per second. Events without * may be used for a misses per second. Events without sharing
* sharing implies multiplexing, that is best avoided, so place * implies multiplexing, that is best avoided, so place
* duration_time in every group. * all tool events in every group.
* *
* Also, there may be no ids/events in the expression parsing * Also, there may be no ids/events in the expression parsing
* context because of constant evaluation, e.g.: * context because of constant evaluation, e.g.:
* event1 if #smt_on else 0 * event1 if #smt_on else 0
* Add a duration_time event to avoid a parse error on an empty * Add a tool event to avoid a parse error on an empty string.
* string.
*/ */
tmp = strdup("duration_time"); perf_tool_event__for_each_event(i) {
char *tmp = strdup(perf_tool_event__to_str(i));
if (!tmp) if (!tmp)
return -ENOMEM; return -ENOMEM;
ids__insert(ids->ids, tmp); ids__insert(ids->ids, tmp);
} }
}
ret = metricgroup__build_event_string(&events, ids, modifier, ret = metricgroup__build_event_string(&events, ids, modifier,
has_constraint); has_constraint);
if (ret) if (ret)
......
...@@ -833,10 +833,31 @@ static int prepare_metric(struct evsel **metric_events, ...@@ -833,10 +833,31 @@ static int prepare_metric(struct evsel **metric_events,
u64 metric_total = 0; u64 metric_total = 0;
int source_count; int source_count;
if (!strcmp(metric_events[i]->name, "duration_time")) { if (evsel__is_tool(metric_events[i])) {
source_count = 1;
switch (metric_events[i]->tool_event) {
case PERF_TOOL_DURATION_TIME:
stats = &walltime_nsecs_stats; stats = &walltime_nsecs_stats;
scale = 1e-9; scale = 1e-9;
source_count = 1; break;
case PERF_TOOL_USER_TIME:
stats = &ru_stats.ru_utime_usec_stat;
scale = 1e-6;
break;
case PERF_TOOL_SYSTEM_TIME:
stats = &ru_stats.ru_stime_usec_stat;
scale = 1e-6;
break;
case PERF_TOOL_NONE:
pr_err("Invalid tool event 'none'");
abort();
case PERF_TOOL_MAX:
pr_err("Invalid tool event 'max'");
abort();
default:
pr_err("Unknown tool event '%s'", evsel__name(metric_events[i]));
abort();
}
} else { } else {
v = saved_value_lookup(metric_events[i], cpu_map_idx, false, v = saved_value_lookup(metric_events[i], cpu_map_idx, false,
STAT_NONE, 0, st, STAT_NONE, 0, st,
......
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