perf stat: Take cgroups into account for shadow stats

As of now it doesn't consider cgroups when collecting shadow stats and
metrics so counter values from different cgroups will be saved in a same
slot. This resulted in incorrect numbers when those cgroups have
different workloads.

For example, let's look at the scenario below: cgroups A and C runs same
workload which burns a cpu while cgroup B runs a light workload.

$ perf stat -a -e cycles,instructions --for-each-cgroup A,B,C sleep 1

Performance counter stats for 'system wide':

3,958,116,522 cycles A
6,722,650,929 instructions A # 2.53 insn per cycle
1,132,741 cycles B
571,743 instructions B # 0.00 insn per cycle
4,007,799,935 cycles C
6,793,181,523 instructions C # 2.56 insn per cycle

1.001050869 seconds time elapsed

When I run 'perf stat' with single workload, it usually shows IPC around
1.7. We can verify it (6,722,650,929.0 / 3,958,116,522 = 1.698) for cgroup A.

But in this case, since cgroups are ignored, cycles are averaged so it
used the lower value for IPC calculation and resulted in around 2.5.

avg cycle: (3958116522 + 1132741 + 4007799935) / 3 = 2655683066
IPC (A) : 6722650929 / 2655683066 = 2.531
IPC (B) : 571743 / 2655683066 = 0.0002
IPC (C) : 6793181523 / 2655683066 = 2.557

We can simply compare cgroup pointers in the evsel and it'll be NULL
when cgroups are not specified. With this patch, I can see correct
numbers like below:

$ perf stat -a -e cycles,instructions --for-each-cgroup A,B,C sleep 1

Performance counter stats for 'system wide':

4,171,051,687 cycles A
7,219,793,922 instructions A # 1.73 insn per cycle
1,051,189 cycles B
583,102 instructions B # 0.55 insn per cycle
4,171,124,710 cycles C
7,192,944,580 instructions C # 1.72 insn per cycle

1.007909814 seconds time elapsed

Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Acked-by: Jiri Olsa <jolsa@redhat.com>
Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com>
Cc: Andi Kleen <ak@linux.intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Jin Yao <yao.jin@linux.intel.com>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lore.kernel.org/lkml/20210115071139.257042-2-namhyung@kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>

authored by Namhyung Kim and committed by Arnaldo Carvalho de Melo a1bf2305 3ff1e718

Changed files
+19 -7
tools
perf
+19 -7
tools/perf/util/stat-shadow.c
··· 8 8 #include "evlist.h" 9 9 #include "expr.h" 10 10 #include "metricgroup.h" 11 + #include "cgroup.h" 11 12 #include <linux/zalloc.h> 12 13 13 14 /* ··· 29 28 enum stat_type type; 30 29 int ctx; 31 30 int cpu; 31 + struct cgroup *cgrp; 32 32 struct runtime_stat *stat; 33 33 struct stats stats; 34 34 u64 metric_total; ··· 58 56 59 57 if (a->ctx != b->ctx) 60 58 return a->ctx - b->ctx; 59 + 60 + if (a->cgrp != b->cgrp) 61 + return (char *)a->cgrp < (char *)b->cgrp ? -1 : +1; 61 62 62 63 if (a->evsel == NULL && b->evsel == NULL) { 63 64 if (a->stat == b->stat) ··· 105 100 bool create, 106 101 enum stat_type type, 107 102 int ctx, 108 - struct runtime_stat *st) 103 + struct runtime_stat *st, 104 + struct cgroup *cgrp) 109 105 { 110 106 struct rblist *rblist; 111 107 struct rb_node *nd; ··· 116 110 .type = type, 117 111 .ctx = ctx, 118 112 .stat = st, 113 + .cgrp = cgrp, 119 114 }; 120 115 121 116 rblist = &st->value_list; ··· 204 197 205 198 struct runtime_stat_data { 206 199 int ctx; 200 + struct cgroup *cgrp; 207 201 }; 208 202 209 203 static void update_runtime_stat(struct runtime_stat *st, ··· 213 205 struct runtime_stat_data *rsd) 214 206 { 215 207 struct saved_value *v = saved_value_lookup(NULL, cpu, true, type, 216 - rsd->ctx, st); 208 + rsd->ctx, st, rsd->cgrp); 217 209 218 210 if (v) 219 211 update_stats(&v->stats, count); ··· 231 223 struct saved_value *v; 232 224 struct runtime_stat_data rsd = { 233 225 .ctx = evsel_context(counter), 226 + .cgrp = counter->cgrp, 234 227 }; 235 228 236 229 count *= counter->scale; ··· 299 290 update_runtime_stat(st, STAT_APERF, cpu, count, &rsd); 300 291 301 292 if (counter->collect_stat) { 302 - v = saved_value_lookup(counter, cpu, true, STAT_NONE, 0, st); 293 + v = saved_value_lookup(counter, cpu, true, STAT_NONE, 0, st, 294 + rsd.cgrp); 303 295 update_stats(&v->stats, count); 304 296 if (counter->metric_leader) 305 297 v->metric_total += count; 306 298 } else if (counter->metric_leader) { 307 299 v = saved_value_lookup(counter->metric_leader, 308 - cpu, true, STAT_NONE, 0, st); 300 + cpu, true, STAT_NONE, 0, st, rsd.cgrp); 309 301 v->metric_total += count; 310 302 v->metric_other++; 311 303 } ··· 448 438 { 449 439 struct saved_value *v; 450 440 451 - v = saved_value_lookup(NULL, cpu, false, type, rsd->ctx, st); 441 + v = saved_value_lookup(NULL, cpu, false, type, rsd->ctx, st, rsd->cgrp); 452 442 if (!v) 453 443 return 0.0; 454 444 ··· 461 451 { 462 452 struct saved_value *v; 463 453 464 - v = saved_value_lookup(NULL, cpu, false, type, rsd->ctx, st); 454 + v = saved_value_lookup(NULL, cpu, false, type, rsd->ctx, st, rsd->cgrp); 465 455 if (!v) 466 456 return 0.0; 467 457 ··· 815 805 scale = 1e-9; 816 806 } else { 817 807 v = saved_value_lookup(metric_events[i], cpu, false, 818 - STAT_NONE, 0, st); 808 + STAT_NONE, 0, st, 809 + metric_events[i]->cgrp); 819 810 if (!v) 820 811 break; 821 812 stats = &v->stats; ··· 944 933 const char *color = NULL; 945 934 struct runtime_stat_data rsd = { 946 935 .ctx = evsel_context(evsel), 936 + .cgrp = evsel->cgrp, 947 937 }; 948 938 struct metric_event *me; 949 939 int num = 1;