Commit 67f8b7eb authored by Namhyung Kim's avatar Namhyung Kim Committed by Arnaldo Carvalho de Melo

perf stat: Support --for-each-cgroup and --metric-only

When we have events for each cgroup, the metric should be printed for
each cgroup separately.  Add print_cgroup_counter() to handle that
situation properly.

Also change print_metric_headers() not to print duplicate headers
by checking cgroups.

  $ perf stat -a --for-each-cgroup system.slice,user.slice --metric-only sleep 1

   Performance counter stats for 'system wide':

                                     GHz       insn per cycle branch-misses of all branches
   system.slice                   3.792                0.61                                3.24%
   user.slice                     3.661                2.32                                0.37%

         1.016111516 seconds time elapsed
Signed-off-by: default avatarNamhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Athira Jajeev <atrajeev@linux.vnet.ibm.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: James Clark <james.clark@arm.com>
Cc: Jiri Olsa <jolsa@kernel.org>
Cc: Kan Liang <kan.liang@linux.intel.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Xing Zhengjun <zhengjun.xing@linux.intel.com>
Link: https://lore.kernel.org/r/20221114230227.1255976-19-namhyung@kernel.orgSigned-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 78670dae
...@@ -168,10 +168,10 @@ static void print_cgroup_json(struct perf_stat_config *config, const char *cgrp_ ...@@ -168,10 +168,10 @@ static void print_cgroup_json(struct perf_stat_config *config, const char *cgrp_
fprintf(config->output, "\"cgroup\" : \"%s\", ", cgrp_name); fprintf(config->output, "\"cgroup\" : \"%s\", ", cgrp_name);
} }
static void print_cgroup(struct perf_stat_config *config, struct evsel *evsel) static void print_cgroup(struct perf_stat_config *config, struct cgroup *cgrp)
{ {
if (nr_cgroups) { if (nr_cgroups || config->cgroup_list) {
const char *cgrp_name = evsel->cgrp ? evsel->cgrp->name : ""; const char *cgrp_name = cgrp ? cgrp->name : "";
if (config->json_output) if (config->json_output)
print_cgroup_json(config, cgrp_name); print_cgroup_json(config, cgrp_name);
...@@ -340,6 +340,7 @@ struct outstate { ...@@ -340,6 +340,7 @@ struct outstate {
int nr; int nr;
struct aggr_cpu_id id; struct aggr_cpu_id id;
struct evsel *evsel; struct evsel *evsel;
struct cgroup *cgrp;
}; };
static void new_line_std(struct perf_stat_config *config __maybe_unused, static void new_line_std(struct perf_stat_config *config __maybe_unused,
...@@ -552,6 +553,9 @@ static void print_metric_header(struct perf_stat_config *config, ...@@ -552,6 +553,9 @@ static void print_metric_header(struct perf_stat_config *config,
os->evsel->priv != os->evsel->evlist->selected->priv) os->evsel->priv != os->evsel->evlist->selected->priv)
return; return;
if (os->evsel->cgrp != os->cgrp)
return;
if (!valid_only_metric(unit)) if (!valid_only_metric(unit))
return; return;
unit = fixunit(tbuf, os->evsel, unit); unit = fixunit(tbuf, os->evsel, unit);
...@@ -642,7 +646,7 @@ static void abs_printout(struct perf_stat_config *config, ...@@ -642,7 +646,7 @@ static void abs_printout(struct perf_stat_config *config,
{ {
aggr_printout(config, evsel, id, nr); aggr_printout(config, evsel, id, nr);
print_counter_value(config, evsel, avg, ok); print_counter_value(config, evsel, avg, ok);
print_cgroup(config, evsel); print_cgroup(config, evsel->cgrp);
} }
static bool is_mixed_hw_group(struct evsel *counter) static bool is_mixed_hw_group(struct evsel *counter)
...@@ -838,7 +842,8 @@ static void print_counter_aggrdata(struct perf_stat_config *config, ...@@ -838,7 +842,8 @@ static void print_counter_aggrdata(struct perf_stat_config *config,
static void print_metric_begin(struct perf_stat_config *config, static void print_metric_begin(struct perf_stat_config *config,
struct evlist *evlist, struct evlist *evlist,
char *prefix, int aggr_idx) char *prefix, int aggr_idx,
struct cgroup *cgrp)
{ {
struct perf_stat_aggr *aggr; struct perf_stat_aggr *aggr;
struct aggr_cpu_id id; struct aggr_cpu_id id;
...@@ -854,6 +859,8 @@ static void print_metric_begin(struct perf_stat_config *config, ...@@ -854,6 +859,8 @@ static void print_metric_begin(struct perf_stat_config *config,
id = config->aggr_map->map[aggr_idx]; id = config->aggr_map->map[aggr_idx];
aggr = &evsel->stats->aggr[aggr_idx]; aggr = &evsel->stats->aggr[aggr_idx];
aggr_printout(config, evsel, id, aggr->nr); aggr_printout(config, evsel, id, aggr->nr);
print_cgroup(config, cgrp);
} }
static void print_metric_end(struct perf_stat_config *config) static void print_metric_end(struct perf_stat_config *config)
...@@ -880,7 +887,7 @@ static void print_aggr(struct perf_stat_config *config, ...@@ -880,7 +887,7 @@ static void print_aggr(struct perf_stat_config *config,
* Without each counter has its own line. * Without each counter has its own line.
*/ */
for (s = 0; s < config->aggr_map->nr; s++) { for (s = 0; s < config->aggr_map->nr; s++) {
print_metric_begin(config, evlist, prefix, s); print_metric_begin(config, evlist, prefix, s, /*cgrp=*/NULL);
evlist__for_each_entry(evlist, counter) { evlist__for_each_entry(evlist, counter) {
if (counter->merged_stat) if (counter->merged_stat)
...@@ -935,7 +942,8 @@ static void print_no_aggr_metric(struct perf_stat_config *config, ...@@ -935,7 +942,8 @@ static void print_no_aggr_metric(struct perf_stat_config *config,
id = aggr_cpu_id__cpu(cpu, /*data=*/NULL); id = aggr_cpu_id__cpu(cpu, /*data=*/NULL);
if (first) { if (first) {
print_metric_begin(config, evlist, prefix, counter_idx); print_metric_begin(config, evlist, prefix,
counter_idx, /*cgrp=*/NULL);
first = false; first = false;
} }
val = ps->aggr[counter_idx].counts.val; val = ps->aggr[counter_idx].counts.val;
...@@ -960,7 +968,7 @@ static void print_metric_headers_std(struct perf_stat_config *config, ...@@ -960,7 +968,7 @@ static void print_metric_headers_std(struct perf_stat_config *config,
if (!no_indent) { if (!no_indent) {
int len = aggr_header_lens[config->aggr_mode]; int len = aggr_header_lens[config->aggr_mode];
if (nr_cgroups) if (nr_cgroups || config->cgroup_list)
len += CGROUP_LEN + 1; len += CGROUP_LEN + 1;
fprintf(config->output, "%*s", len, ""); fprintf(config->output, "%*s", len, "");
...@@ -1012,6 +1020,9 @@ static void print_metric_headers(struct perf_stat_config *config, ...@@ -1012,6 +1020,9 @@ static void print_metric_headers(struct perf_stat_config *config,
if (config->iostat_run) if (config->iostat_run)
iostat_print_header_prefix(config); iostat_print_header_prefix(config);
if (config->cgroup_list)
os.cgrp = evlist__first(evlist)->cgrp;
/* Print metrics headers only */ /* Print metrics headers only */
evlist__for_each_entry(evlist, counter) { evlist__for_each_entry(evlist, counter) {
os.evsel = counter; os.evsel = counter;
...@@ -1305,6 +1316,28 @@ static void print_percore(struct perf_stat_config *config, ...@@ -1305,6 +1316,28 @@ static void print_percore(struct perf_stat_config *config,
fputc('\n', output); fputc('\n', output);
} }
static void print_cgroup_counter(struct perf_stat_config *config, struct evlist *evlist,
char *prefix)
{
struct cgroup *cgrp = NULL;
struct evsel *counter;
evlist__for_each_entry(evlist, counter) {
if (cgrp != counter->cgrp) {
if (cgrp != NULL)
print_metric_end(config);
cgrp = counter->cgrp;
print_metric_begin(config, evlist, prefix,
/*aggr_idx=*/0, cgrp);
}
print_counter(config, counter, prefix);
}
if (cgrp)
print_metric_end(config);
}
void evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config, void evlist__print_counters(struct evlist *evlist, struct perf_stat_config *config,
struct target *_target, struct timespec *ts, int argc, const char **argv) struct target *_target, struct timespec *ts, int argc, const char **argv)
{ {
...@@ -1332,11 +1365,14 @@ void evlist__print_counters(struct evlist *evlist, struct perf_stat_config *conf ...@@ -1332,11 +1365,14 @@ void evlist__print_counters(struct evlist *evlist, struct perf_stat_config *conf
break; break;
case AGGR_THREAD: case AGGR_THREAD:
case AGGR_GLOBAL: case AGGR_GLOBAL:
if (config->iostat_run) if (config->iostat_run) {
iostat_print_counters(evlist, config, ts, prefix = buf, iostat_print_counters(evlist, config, ts, prefix = buf,
print_counter); print_counter);
else { } else if (config->cgroup_list) {
print_metric_begin(config, evlist, prefix, /*aggr_idx=*/0); print_cgroup_counter(config, evlist, prefix);
} else {
print_metric_begin(config, evlist, prefix,
/*aggr_idx=*/0, /*cgrp=*/NULL);
evlist__for_each_entry(evlist, counter) { evlist__for_each_entry(evlist, counter) {
print_counter(config, counter, prefix); print_counter(config, counter, 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