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

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