perf stat: Hide runtime_stat
[linux-2.6-block.git] / tools / perf / util / stat-shadow.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
cb94a02e 2#include <math.h>
f87027b9
JO
3#include <stdio.h>
4#include "evsel.h"
5#include "stat.h"
6#include "color.h"
cb94a02e 7#include "debug.h"
fb4605ba 8#include "pmu.h"
37932c18
AK
9#include "rblist.h"
10#include "evlist.h"
11#include "expr.h"
b18f3e36 12#include "metricgroup.h"
a1bf2305 13#include "cgroup.h"
6859bc0e 14#include "units.h"
d8f9da24 15#include <linux/zalloc.h>
f07952b1 16#include "iostat.h"
bd560973 17#include "util/hashmap.h"
f87027b9 18
44d49a60
AK
19/*
20 * AGGR_GLOBAL: Use CPU 0
21 * AGGR_SOCKET: Use first CPU of socket
db5742b6 22 * AGGR_DIE: Use first CPU of die
44d49a60
AK
23 * AGGR_CORE: Use first CPU of core
24 * AGGR_NONE: Use matching CPU
25 * AGGR_THREAD: Not supported?
26 */
f87027b9
JO
27
28struct stats walltime_nsecs_stats;
c735b0a5 29struct rusage_stats ru_stats;
f87027b9 30
cc26ffaa
IR
31static struct runtime_stat {
32 struct rblist value_list;
33} rt_stat;
34
758bc8e6
IR
35enum {
36 CTX_BIT_USER = 1 << 0,
37 CTX_BIT_KERNEL = 1 << 1,
38 CTX_BIT_HV = 1 << 2,
39 CTX_BIT_HOST = 1 << 3,
40 CTX_BIT_IDLE = 1 << 4,
41 CTX_BIT_MAX = 1 << 5,
42};
43
44enum stat_type {
45 STAT_NONE = 0,
46 STAT_NSECS,
47 STAT_CYCLES,
48 STAT_STALLED_CYCLES_FRONT,
49 STAT_STALLED_CYCLES_BACK,
50 STAT_BRANCHES,
51 STAT_CACHEREFS,
52 STAT_L1_DCACHE,
53 STAT_L1_ICACHE,
54 STAT_LL_CACHE,
55 STAT_ITLB_CACHE,
56 STAT_DTLB_CACHE,
57 STAT_MAX
58};
59
37932c18
AK
60struct saved_value {
61 struct rb_node rb_node;
32dcd021 62 struct evsel *evsel;
49cd456a
JY
63 enum stat_type type;
64 int ctx;
87ae87fd 65 int map_idx; /* cpu or thread map index */
a1bf2305 66 struct cgroup *cgrp;
37932c18 67 struct stats stats;
f01642e4
JY
68 u64 metric_total;
69 int metric_other;
37932c18
AK
70};
71
72static int saved_value_cmp(struct rb_node *rb_node, const void *entry)
73{
74 struct saved_value *a = container_of(rb_node,
75 struct saved_value,
76 rb_node);
77 const struct saved_value *b = entry;
78
dfca2d69
NK
79 if (a->map_idx != b->map_idx)
80 return a->map_idx - b->map_idx;
49cd456a
JY
81
82 /*
83 * Previously the rbtree was used to link generic metrics.
84 * The keys were evsel/cpu. Now the rbtree is extended to support
85 * per-thread shadow stats. For shadow stats case, the keys
86 * are cpu/type/ctx/stat (evsel is NULL). For generic metrics
87 * case, the keys are still evsel/cpu (type/ctx/stat are 0 or NULL).
88 */
89 if (a->type != b->type)
90 return a->type - b->type;
91
92 if (a->ctx != b->ctx)
93 return a->ctx - b->ctx;
94
a1bf2305
NK
95 if (a->cgrp != b->cgrp)
96 return (char *)a->cgrp < (char *)b->cgrp ? -1 : +1;
97
5e97665f
AK
98 if (a->evsel == b->evsel)
99 return 0;
100 if ((char *)a->evsel < (char *)b->evsel)
101 return -1;
102 return +1;
37932c18
AK
103}
104
105static struct rb_node *saved_value_new(struct rblist *rblist __maybe_unused,
106 const void *entry)
107{
108 struct saved_value *nd = malloc(sizeof(struct saved_value));
109
110 if (!nd)
111 return NULL;
112 memcpy(nd, entry, sizeof(struct saved_value));
113 return &nd->rb_node;
114}
115
b984aff7
JY
116static void saved_value_delete(struct rblist *rblist __maybe_unused,
117 struct rb_node *rb_node)
118{
119 struct saved_value *v;
120
121 BUG_ON(!rb_node);
122 v = container_of(rb_node, struct saved_value, rb_node);
123 free(v);
124}
125
32dcd021 126static struct saved_value *saved_value_lookup(struct evsel *evsel,
dfca2d69 127 int map_idx,
1fcd0394
JY
128 bool create,
129 enum stat_type type,
130 int ctx,
a1bf2305 131 struct cgroup *cgrp)
37932c18 132{
1fcd0394 133 struct rblist *rblist;
37932c18
AK
134 struct rb_node *nd;
135 struct saved_value dm = {
dfca2d69 136 .map_idx = map_idx,
37932c18 137 .evsel = evsel,
1fcd0394
JY
138 .type = type,
139 .ctx = ctx,
a1bf2305 140 .cgrp = cgrp,
37932c18 141 };
1fcd0394 142
cc26ffaa 143 rblist = &rt_stat.value_list;
1fcd0394 144
3ff1e718
NK
145 /* don't use context info for clock events */
146 if (type == STAT_NSECS)
147 dm.ctx = 0;
148
1fcd0394 149 nd = rblist__find(rblist, &dm);
37932c18
AK
150 if (nd)
151 return container_of(nd, struct saved_value, rb_node);
152 if (create) {
1fcd0394
JY
153 rblist__add_node(rblist, &dm);
154 nd = rblist__find(rblist, &dm);
37932c18
AK
155 if (nd)
156 return container_of(nd, struct saved_value, rb_node);
157 }
158 return NULL;
159}
160
cc26ffaa 161void perf_stat__init_shadow_stats(void)
8efb2df1 162{
cc26ffaa 163 struct rblist *rblist = &rt_stat.value_list;
8efb2df1
JY
164
165 rblist__init(rblist);
166 rblist->node_cmp = saved_value_cmp;
167 rblist->node_new = saved_value_new;
168 rblist->node_delete = saved_value_delete;
169}
170
32dcd021 171static int evsel_context(struct evsel *evsel)
f87027b9
JO
172{
173 int ctx = 0;
174
1fc632ce 175 if (evsel->core.attr.exclude_kernel)
f87027b9 176 ctx |= CTX_BIT_KERNEL;
1fc632ce 177 if (evsel->core.attr.exclude_user)
f87027b9 178 ctx |= CTX_BIT_USER;
1fc632ce 179 if (evsel->core.attr.exclude_hv)
f87027b9 180 ctx |= CTX_BIT_HV;
1fc632ce 181 if (evsel->core.attr.exclude_host)
f87027b9 182 ctx |= CTX_BIT_HOST;
1fc632ce 183 if (evsel->core.attr.exclude_idle)
f87027b9
JO
184 ctx |= CTX_BIT_IDLE;
185
186 return ctx;
187}
188
cc26ffaa 189void perf_stat__reset_shadow_per_stat(void)
f87027b9 190{
6a1e2c5c 191 struct rblist *rblist;
37932c18
AK
192 struct rb_node *pos, *next;
193
cc26ffaa 194 rblist = &rt_stat.value_list;
ca227029 195 next = rb_first_cached(&rblist->entries);
37932c18
AK
196 while (next) {
197 pos = next;
198 next = rb_next(pos);
199 memset(&container_of(pos, struct saved_value, rb_node)->stats,
200 0,
201 sizeof(struct stats));
202 }
f87027b9
JO
203}
204
6a1e2c5c
JY
205void perf_stat__reset_shadow_stats(void)
206{
cc26ffaa 207 perf_stat__reset_shadow_per_stat();
6a1e2c5c 208 memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats));
c735b0a5 209 memset(&ru_stats, 0, sizeof(ru_stats));
6a1e2c5c
JY
210}
211
3ff1e718
NK
212struct runtime_stat_data {
213 int ctx;
a1bf2305 214 struct cgroup *cgrp;
3ff1e718
NK
215};
216
cc26ffaa 217static void update_runtime_stat(enum stat_type type,
dfca2d69 218 int map_idx, u64 count,
3ff1e718 219 struct runtime_stat_data *rsd)
1fcd0394 220{
dfca2d69 221 struct saved_value *v = saved_value_lookup(NULL, map_idx, true, type,
cc26ffaa 222 rsd->ctx, rsd->cgrp);
1fcd0394
JY
223
224 if (v)
225 update_stats(&v->stats, count);
226}
227
f87027b9
JO
228/*
229 * Update various tracking values we maintain to print
230 * more semantic information such as miss/hit ratios,
231 * instruction rates, etc:
232 */
32dcd021 233void perf_stat__update_shadow_stats(struct evsel *counter, u64 count,
cc26ffaa 234 int map_idx)
f87027b9 235{
57ddf091 236 u64 count_ns = count;
f01642e4 237 struct saved_value *v;
3ff1e718
NK
238 struct runtime_stat_data rsd = {
239 .ctx = evsel_context(counter),
a1bf2305 240 .cgrp = counter->cgrp,
3ff1e718 241 };
54830dd0
JO
242 count *= counter->scale;
243
c754c382 244 if (evsel__is_clock(counter))
cc26ffaa 245 update_runtime_stat(STAT_NSECS, map_idx, count_ns, &rsd);
c754c382 246 else if (evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
cc26ffaa 247 update_runtime_stat(STAT_CYCLES, map_idx, count, &rsd);
c754c382 248 else if (evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND))
cc26ffaa 249 update_runtime_stat(STAT_STALLED_CYCLES_FRONT,
dfca2d69 250 map_idx, count, &rsd);
c754c382 251 else if (evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND))
cc26ffaa 252 update_runtime_stat(STAT_STALLED_CYCLES_BACK,
dfca2d69 253 map_idx, count, &rsd);
c754c382 254 else if (evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS))
cc26ffaa 255 update_runtime_stat(STAT_BRANCHES, map_idx, count, &rsd);
c754c382 256 else if (evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES))
cc26ffaa 257 update_runtime_stat(STAT_CACHEREFS, map_idx, count, &rsd);
c754c382 258 else if (evsel__match(counter, HW_CACHE, HW_CACHE_L1D))
cc26ffaa 259 update_runtime_stat(STAT_L1_DCACHE, map_idx, count, &rsd);
c754c382 260 else if (evsel__match(counter, HW_CACHE, HW_CACHE_L1I))
cc26ffaa 261 update_runtime_stat(STAT_L1_ICACHE, map_idx, count, &rsd);
c754c382 262 else if (evsel__match(counter, HW_CACHE, HW_CACHE_LL))
cc26ffaa 263 update_runtime_stat(STAT_LL_CACHE, map_idx, count, &rsd);
c754c382 264 else if (evsel__match(counter, HW_CACHE, HW_CACHE_DTLB))
cc26ffaa 265 update_runtime_stat(STAT_DTLB_CACHE, map_idx, count, &rsd);
c754c382 266 else if (evsel__match(counter, HW_CACHE, HW_CACHE_ITLB))
cc26ffaa 267 update_runtime_stat(STAT_ITLB_CACHE, map_idx, count, &rsd);
37932c18
AK
268
269 if (counter->collect_stat) {
cc26ffaa 270 v = saved_value_lookup(counter, map_idx, true, STAT_NONE, 0,
a1bf2305 271 rsd.cgrp);
54830dd0 272 update_stats(&v->stats, count);
f01642e4
JY
273 if (counter->metric_leader)
274 v->metric_total += count;
37f322cd 275 } else if (counter->metric_leader && !counter->merged_stat) {
f01642e4 276 v = saved_value_lookup(counter->metric_leader,
cc26ffaa 277 map_idx, true, STAT_NONE, 0, rsd.cgrp);
f01642e4
JY
278 v->metric_total += count;
279 v->metric_other++;
37932c18 280 }
f87027b9
JO
281}
282
283/* used for get_ratio_color() */
284enum grc_type {
285 GRC_STALLED_CYCLES_FE,
286 GRC_STALLED_CYCLES_BE,
287 GRC_CACHE_MISSES,
288 GRC_MAX_NR
289};
290
291static const char *get_ratio_color(enum grc_type type, double ratio)
292{
293 static const double grc_table[GRC_MAX_NR][3] = {
294 [GRC_STALLED_CYCLES_FE] = { 50.0, 30.0, 10.0 },
295 [GRC_STALLED_CYCLES_BE] = { 75.0, 50.0, 20.0 },
296 [GRC_CACHE_MISSES] = { 20.0, 10.0, 5.0 },
297 };
298 const char *color = PERF_COLOR_NORMAL;
299
300 if (ratio > grc_table[type][0])
301 color = PERF_COLOR_RED;
302 else if (ratio > grc_table[type][1])
303 color = PERF_COLOR_MAGENTA;
304 else if (ratio > grc_table[type][2])
305 color = PERF_COLOR_YELLOW;
306
307 return color;
308}
309
cc26ffaa 310static double runtime_stat_avg(enum stat_type type, int map_idx,
3ff1e718 311 struct runtime_stat_data *rsd)
e0128b30
JY
312{
313 struct saved_value *v;
314
cc26ffaa 315 v = saved_value_lookup(NULL, map_idx, false, type, rsd->ctx, rsd->cgrp);
e0128b30
JY
316 if (!v)
317 return 0.0;
318
319 return avg_stats(&v->stats);
320}
321
cc26ffaa 322static double runtime_stat_n(enum stat_type type, int map_idx,
3ff1e718 323 struct runtime_stat_data *rsd)
e0128b30
JY
324{
325 struct saved_value *v;
326
cc26ffaa 327 v = saved_value_lookup(NULL, map_idx, false, type, rsd->ctx, rsd->cgrp);
e0128b30
JY
328 if (!v)
329 return 0.0;
330
331 return v->stats.n;
332}
333
6ca9a082 334static void print_stalled_cycles_frontend(struct perf_stat_config *config,
dfca2d69 335 int map_idx, double avg,
e0128b30 336 struct perf_stat_output_ctx *out,
3ff1e718 337 struct runtime_stat_data *rsd)
f87027b9
JO
338{
339 double total, ratio = 0.0;
340 const char *color;
f87027b9 341
cc26ffaa 342 total = runtime_stat_avg(STAT_CYCLES, map_idx, rsd);
f87027b9
JO
343
344 if (total)
345 ratio = avg / total * 100.0;
346
347 color = get_ratio_color(GRC_STALLED_CYCLES_FE, ratio);
348
140aeadc 349 if (ratio)
6ca9a082 350 out->print_metric(config, out->ctx, color, "%7.2f%%", "frontend cycles idle",
140aeadc
AK
351 ratio);
352 else
6ca9a082 353 out->print_metric(config, out->ctx, NULL, NULL, "frontend cycles idle", 0);
f87027b9
JO
354}
355
6ca9a082 356static void print_stalled_cycles_backend(struct perf_stat_config *config,
dfca2d69 357 int map_idx, double avg,
e0128b30 358 struct perf_stat_output_ctx *out,
3ff1e718 359 struct runtime_stat_data *rsd)
f87027b9
JO
360{
361 double total, ratio = 0.0;
362 const char *color;
f87027b9 363
cc26ffaa 364 total = runtime_stat_avg(STAT_CYCLES, map_idx, rsd);
f87027b9
JO
365
366 if (total)
367 ratio = avg / total * 100.0;
368
369 color = get_ratio_color(GRC_STALLED_CYCLES_BE, ratio);
370
6ca9a082 371 out->print_metric(config, out->ctx, color, "%7.2f%%", "backend cycles idle", ratio);
f87027b9
JO
372}
373
6ca9a082 374static void print_branch_misses(struct perf_stat_config *config,
dfca2d69 375 int map_idx, double avg,
e0128b30 376 struct perf_stat_output_ctx *out,
3ff1e718 377 struct runtime_stat_data *rsd)
f87027b9
JO
378{
379 double total, ratio = 0.0;
380 const char *color;
f87027b9 381
cc26ffaa 382 total = runtime_stat_avg(STAT_BRANCHES, map_idx, rsd);
f87027b9
JO
383
384 if (total)
385 ratio = avg / total * 100.0;
386
387 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
388
6ca9a082 389 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all branches", ratio);
f87027b9
JO
390}
391
6ca9a082 392static void print_l1_dcache_misses(struct perf_stat_config *config,
dfca2d69 393 int map_idx, double avg,
e0128b30 394 struct perf_stat_output_ctx *out,
3ff1e718 395 struct runtime_stat_data *rsd)
f87027b9
JO
396{
397 double total, ratio = 0.0;
398 const char *color;
f87027b9 399
cc26ffaa 400 total = runtime_stat_avg(STAT_L1_DCACHE, map_idx, rsd);
f87027b9
JO
401
402 if (total)
403 ratio = avg / total * 100.0;
404
405 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
406
ce9c13f3 407 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all L1-dcache accesses", ratio);
f87027b9
JO
408}
409
6ca9a082 410static void print_l1_icache_misses(struct perf_stat_config *config,
dfca2d69 411 int map_idx, double avg,
e0128b30 412 struct perf_stat_output_ctx *out,
3ff1e718 413 struct runtime_stat_data *rsd)
f87027b9
JO
414{
415 double total, ratio = 0.0;
416 const char *color;
f87027b9 417
cc26ffaa 418 total = runtime_stat_avg(STAT_L1_ICACHE, map_idx, rsd);
f87027b9
JO
419
420 if (total)
421 ratio = avg / total * 100.0;
422
423 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
ce9c13f3 424 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all L1-icache accesses", ratio);
f87027b9
JO
425}
426
6ca9a082 427static void print_dtlb_cache_misses(struct perf_stat_config *config,
dfca2d69 428 int map_idx, double avg,
e0128b30 429 struct perf_stat_output_ctx *out,
3ff1e718 430 struct runtime_stat_data *rsd)
f87027b9
JO
431{
432 double total, ratio = 0.0;
433 const char *color;
f87027b9 434
cc26ffaa 435 total = runtime_stat_avg(STAT_DTLB_CACHE, map_idx, rsd);
f87027b9
JO
436
437 if (total)
438 ratio = avg / total * 100.0;
439
440 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
ce9c13f3 441 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all dTLB cache accesses", ratio);
f87027b9
JO
442}
443
6ca9a082 444static void print_itlb_cache_misses(struct perf_stat_config *config,
dfca2d69 445 int map_idx, double avg,
e0128b30 446 struct perf_stat_output_ctx *out,
3ff1e718 447 struct runtime_stat_data *rsd)
f87027b9
JO
448{
449 double total, ratio = 0.0;
450 const char *color;
f87027b9 451
cc26ffaa 452 total = runtime_stat_avg(STAT_ITLB_CACHE, map_idx, rsd);
f87027b9
JO
453
454 if (total)
455 ratio = avg / total * 100.0;
456
457 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
ce9c13f3 458 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all iTLB cache accesses", ratio);
f87027b9
JO
459}
460
6ca9a082 461static void print_ll_cache_misses(struct perf_stat_config *config,
dfca2d69 462 int map_idx, double avg,
e0128b30 463 struct perf_stat_output_ctx *out,
3ff1e718 464 struct runtime_stat_data *rsd)
f87027b9
JO
465{
466 double total, ratio = 0.0;
467 const char *color;
f87027b9 468
cc26ffaa 469 total = runtime_stat_avg(STAT_LL_CACHE, map_idx, rsd);
f87027b9
JO
470
471 if (total)
472 ratio = avg / total * 100.0;
473
474 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
ce9c13f3 475 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all LL-cache accesses", ratio);
f87027b9
JO
476}
477
2cfaa853 478static int prepare_metric(struct evsel **metric_events,
fc393839 479 struct metric_ref *metric_refs,
2cfaa853 480 struct expr_parse_ctx *pctx,
cc26ffaa 481 int map_idx)
bba49af8 482{
2cfaa853 483 double scale;
ec5c5b3d 484 char *n;
fc393839 485 int i, j, ret;
bba49af8 486
bba49af8
AK
487 for (i = 0; metric_events[i]; i++) {
488 struct saved_value *v;
fd48aad9 489 struct stats *stats;
f01642e4 490 u64 metric_total = 0;
9aba0ada 491 int source_count;
fd48aad9 492
9aa09230 493 if (evsel__is_tool(metric_events[i])) {
9aba0ada 494 source_count = 1;
9aa09230
IR
495 switch (metric_events[i]->tool_event) {
496 case PERF_TOOL_DURATION_TIME:
497 stats = &walltime_nsecs_stats;
498 scale = 1e-9;
499 break;
500 case PERF_TOOL_USER_TIME:
501 stats = &ru_stats.ru_utime_usec_stat;
502 scale = 1e-6;
503 break;
504 case PERF_TOOL_SYSTEM_TIME:
505 stats = &ru_stats.ru_stime_usec_stat;
506 scale = 1e-6;
507 break;
508 case PERF_TOOL_NONE:
509 pr_err("Invalid tool event 'none'");
510 abort();
511 case PERF_TOOL_MAX:
512 pr_err("Invalid tool event 'max'");
513 abort();
514 default:
515 pr_err("Unknown tool event '%s'", evsel__name(metric_events[i]));
516 abort();
517 }
fd48aad9 518 } else {
dfca2d69 519 v = saved_value_lookup(metric_events[i], map_idx, false,
cc26ffaa 520 STAT_NONE, 0,
a1bf2305 521 metric_events[i]->cgrp);
fd48aad9
AK
522 if (!v)
523 break;
524 stats = &v->stats;
8cff7490
IR
525 /*
526 * If an event was scaled during stat gathering, reverse
527 * the scale before computing the metric.
528 */
529 scale = 1.0 / metric_events[i]->scale;
530
9aba0ada 531 source_count = evsel__source_count(metric_events[i]);
f01642e4
JY
532
533 if (v->metric_other)
8cff7490 534 metric_total = v->metric_total * scale;
fd48aad9 535 }
ec5c5b3d 536 n = strdup(evsel__metric_id(metric_events[i]));
e3a94273 537 if (!n)
2cfaa853 538 return -ENOMEM;
ec5c5b3d 539
9aba0ada
IR
540 expr__add_id_val_source_count(pctx, n,
541 metric_total ? : avg_stats(stats) * scale,
542 source_count);
bba49af8 543 }
f01642e4 544
fc393839
JO
545 for (j = 0; metric_refs && metric_refs[j].metric_name; j++) {
546 ret = expr__add_ref(pctx, &metric_refs[j]);
547 if (ret)
548 return ret;
549 }
550
2cfaa853
JO
551 return i;
552}
553
554static void generic_metric(struct perf_stat_config *config,
555 const char *metric_expr,
d0a3052f 556 const char *metric_threshold,
2cfaa853 557 struct evsel **metric_events,
fc393839 558 struct metric_ref *metric_refs,
2cfaa853
JO
559 char *name,
560 const char *metric_name,
561 const char *metric_unit,
562 int runtime,
dfca2d69 563 int map_idx,
cc26ffaa 564 struct perf_stat_output_ctx *out)
2cfaa853
JO
565{
566 print_metric_t print_metric = out->print_metric;
cb94a02e 567 struct expr_parse_ctx *pctx;
d0a3052f 568 double ratio, scale, threshold;
2cfaa853
JO
569 int i;
570 void *ctxp = out->ctx;
d0a3052f 571 const char *color = NULL;
2cfaa853 572
cb94a02e
IR
573 pctx = expr__ctx_new();
574 if (!pctx)
2cfaa853
JO
575 return;
576
1725e9cd
IR
577 if (config->user_requested_cpu_list)
578 pctx->sctx.user_requested_cpu_list = strdup(config->user_requested_cpu_list);
1a6abdde 579 pctx->sctx.runtime = runtime;
1725e9cd 580 pctx->sctx.system_wide = config->system_wide;
cc26ffaa 581 i = prepare_metric(metric_events, metric_refs, pctx, map_idx);
cb94a02e
IR
582 if (i < 0) {
583 expr__ctx_free(pctx);
584 return;
585 }
bba49af8 586 if (!metric_events[i]) {
fa831fbb 587 if (expr__parse(&ratio, pctx, metric_expr) == 0) {
287f2649
JY
588 char *unit;
589 char metric_bf[64];
590
d0a3052f 591 if (metric_threshold &&
1fd09e29
IR
592 expr__parse(&threshold, pctx, metric_threshold) == 0 &&
593 !isnan(threshold)) {
d0a3052f
IR
594 color = fpclassify(threshold) == FP_ZERO
595 ? PERF_COLOR_GREEN : PERF_COLOR_RED;
596 }
597
287f2649
JY
598 if (metric_unit && metric_name) {
599 if (perf_pmu__convert_scale(metric_unit,
600 &unit, &scale) >= 0) {
601 ratio *= scale;
602 }
1e1a873d
KJ
603 if (strstr(metric_expr, "?"))
604 scnprintf(metric_bf, sizeof(metric_bf),
605 "%s %s_%d", unit, metric_name, runtime);
606 else
607 scnprintf(metric_bf, sizeof(metric_bf),
287f2649 608 "%s %s", unit, metric_name);
1e1a873d 609
d0a3052f 610 print_metric(config, ctxp, color, "%8.1f",
287f2649
JY
611 metric_bf, ratio);
612 } else {
d0a3052f 613 print_metric(config, ctxp, color, "%8.2f",
287f2649
JY
614 metric_name ?
615 metric_name :
616 out->force_header ? name : "",
617 ratio);
618 }
619 } else {
d0a3052f 620 print_metric(config, ctxp, color, /*unit=*/NULL,
4ed962eb
AK
621 out->force_header ?
622 (metric_name ? metric_name : name) : "", 0);
287f2649 623 }
8358f698 624 } else {
d0a3052f 625 print_metric(config, ctxp, color, /*unit=*/NULL,
8358f698
JY
626 out->force_header ?
627 (metric_name ? metric_name : name) : "", 0);
628 }
e3a94273 629
cb94a02e 630 expr__ctx_free(pctx);
bba49af8
AK
631}
632
cc26ffaa 633double test_generic_metric(struct metric_expr *mexp, int map_idx)
6d432c4c 634{
cb94a02e 635 struct expr_parse_ctx *pctx;
437822bf 636 double ratio = 0.0;
6d432c4c 637
cb94a02e
IR
638 pctx = expr__ctx_new();
639 if (!pctx)
640 return NAN;
641
cc26ffaa 642 if (prepare_metric(mexp->metric_events, mexp->metric_refs, pctx, map_idx) < 0)
437822bf 643 goto out;
6d432c4c 644
fa831fbb 645 if (expr__parse(&ratio, pctx, mexp->metric_expr))
437822bf 646 ratio = 0.0;
6d432c4c 647
437822bf 648out:
cb94a02e 649 expr__ctx_free(pctx);
6d432c4c
JO
650 return ratio;
651}
652
6ca9a082 653void perf_stat__print_shadow_stats(struct perf_stat_config *config,
32dcd021 654 struct evsel *evsel,
dfca2d69 655 double avg, int map_idx,
b18f3e36 656 struct perf_stat_output_ctx *out,
cc26ffaa 657 struct rblist *metric_events)
f87027b9 658{
140aeadc
AK
659 void *ctxp = out->ctx;
660 print_metric_t print_metric = out->print_metric;
d6964c5b 661 double total, ratio = 0.0;
3ff1e718
NK
662 struct runtime_stat_data rsd = {
663 .ctx = evsel_context(evsel),
a1bf2305 664 .cgrp = evsel->cgrp,
3ff1e718 665 };
b18f3e36
AK
666 struct metric_event *me;
667 int num = 1;
f87027b9 668
f07952b1
AA
669 if (config->iostat_run) {
670 iostat_print_metric(config, evsel, out);
671 } else if (evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
cc26ffaa 672 total = runtime_stat_avg(STAT_CYCLES, map_idx, &rsd);
e0128b30 673
f87027b9
JO
674 if (total) {
675 ratio = avg / total;
6ca9a082 676 print_metric(config, ctxp, NULL, "%7.2f ",
140aeadc 677 "insn per cycle", ratio);
f87027b9 678 } else {
6ca9a082 679 print_metric(config, ctxp, NULL, NULL, "insn per cycle", 0);
f87027b9 680 }
e0128b30 681
cc26ffaa 682 total = runtime_stat_avg(STAT_STALLED_CYCLES_FRONT, map_idx, &rsd);
e0128b30 683
cc26ffaa 684 total = max(total, runtime_stat_avg(STAT_STALLED_CYCLES_BACK,
dfca2d69 685 map_idx, &rsd));
f87027b9
JO
686
687 if (total && avg) {
6ca9a082 688 out->new_line(config, ctxp);
f87027b9 689 ratio = total / avg;
6ca9a082 690 print_metric(config, ctxp, NULL, "%7.2f ",
140aeadc
AK
691 "stalled cycles per insn",
692 ratio);
f87027b9 693 }
c754c382 694 } else if (evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES)) {
cc26ffaa
IR
695 if (runtime_stat_n(STAT_BRANCHES, map_idx, &rsd) != 0)
696 print_branch_misses(config, map_idx, avg, out, &rsd);
140aeadc 697 else
6ca9a082 698 print_metric(config, ctxp, NULL, NULL, "of all branches", 0);
f87027b9 699 } else if (
1fc632ce
JO
700 evsel->core.attr.type == PERF_TYPE_HW_CACHE &&
701 evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_L1D |
f87027b9 702 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
140aeadc 703 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
e0128b30 704
cc26ffaa
IR
705 if (runtime_stat_n(STAT_L1_DCACHE, map_idx, &rsd) != 0)
706 print_l1_dcache_misses(config, map_idx, avg, out, &rsd);
140aeadc 707 else
ce9c13f3 708 print_metric(config, ctxp, NULL, NULL, "of all L1-dcache accesses", 0);
f87027b9 709 } else if (
1fc632ce
JO
710 evsel->core.attr.type == PERF_TYPE_HW_CACHE &&
711 evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_L1I |
f87027b9 712 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
140aeadc 713 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
e0128b30 714
cc26ffaa
IR
715 if (runtime_stat_n(STAT_L1_ICACHE, map_idx, &rsd) != 0)
716 print_l1_icache_misses(config, map_idx, avg, out, &rsd);
140aeadc 717 else
ce9c13f3 718 print_metric(config, ctxp, NULL, NULL, "of all L1-icache accesses", 0);
f87027b9 719 } else if (
1fc632ce
JO
720 evsel->core.attr.type == PERF_TYPE_HW_CACHE &&
721 evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_DTLB |
f87027b9 722 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
140aeadc 723 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
e0128b30 724
cc26ffaa
IR
725 if (runtime_stat_n(STAT_DTLB_CACHE, map_idx, &rsd) != 0)
726 print_dtlb_cache_misses(config, map_idx, avg, out, &rsd);
140aeadc 727 else
ce9c13f3 728 print_metric(config, ctxp, NULL, NULL, "of all dTLB cache accesses", 0);
f87027b9 729 } else if (
1fc632ce
JO
730 evsel->core.attr.type == PERF_TYPE_HW_CACHE &&
731 evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_ITLB |
f87027b9 732 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
140aeadc 733 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
e0128b30 734
cc26ffaa
IR
735 if (runtime_stat_n(STAT_ITLB_CACHE, map_idx, &rsd) != 0)
736 print_itlb_cache_misses(config, map_idx, avg, out, &rsd);
140aeadc 737 else
ce9c13f3 738 print_metric(config, ctxp, NULL, NULL, "of all iTLB cache accesses", 0);
f87027b9 739 } else if (
1fc632ce
JO
740 evsel->core.attr.type == PERF_TYPE_HW_CACHE &&
741 evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_LL |
f87027b9 742 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
140aeadc 743 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
e0128b30 744
cc26ffaa
IR
745 if (runtime_stat_n(STAT_LL_CACHE, map_idx, &rsd) != 0)
746 print_ll_cache_misses(config, map_idx, avg, out, &rsd);
140aeadc 747 else
ce9c13f3 748 print_metric(config, ctxp, NULL, NULL, "of all LL-cache accesses", 0);
c754c382 749 } else if (evsel__match(evsel, HARDWARE, HW_CACHE_MISSES)) {
cc26ffaa 750 total = runtime_stat_avg(STAT_CACHEREFS, map_idx, &rsd);
f87027b9
JO
751
752 if (total)
753 ratio = avg * 100 / total;
754
cc26ffaa 755 if (runtime_stat_n(STAT_CACHEREFS, map_idx, &rsd) != 0)
6ca9a082 756 print_metric(config, ctxp, NULL, "%8.3f %%",
140aeadc
AK
757 "of all cache refs", ratio);
758 else
6ca9a082 759 print_metric(config, ctxp, NULL, NULL, "of all cache refs", 0);
c754c382 760 } else if (evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) {
cc26ffaa 761 print_stalled_cycles_frontend(config, map_idx, avg, out, &rsd);
c754c382 762 } else if (evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_BACKEND)) {
cc26ffaa 763 print_stalled_cycles_backend(config, map_idx, avg, out, &rsd);
c754c382 764 } else if (evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) {
cc26ffaa 765 total = runtime_stat_avg(STAT_NSECS, map_idx, &rsd);
f87027b9
JO
766
767 if (total) {
768 ratio = avg / total;
6ca9a082 769 print_metric(config, ctxp, NULL, "%8.3f", "GHz", ratio);
f87027b9 770 } else {
6ca9a082 771 print_metric(config, ctxp, NULL, NULL, "Ghz", 0);
f87027b9 772 }
c754c382 773 } else if (evsel__is_clock(evsel)) {
4579ecc8 774 if ((ratio = avg_stats(&walltime_nsecs_stats)) != 0)
6ca9a082 775 print_metric(config, ctxp, NULL, "%8.3f", "CPUs utilized",
0aa802a7 776 avg / (ratio * evsel->scale));
4579ecc8 777 else
6ca9a082 778 print_metric(config, ctxp, NULL, NULL, "CPUs utilized", 0);
cc26ffaa 779 } else if (runtime_stat_n(STAT_NSECS, map_idx, &rsd) != 0) {
6859bc0e
CD
780 char unit = ' ';
781 char unit_buf[10] = "/sec";
f87027b9 782
cc26ffaa 783 total = runtime_stat_avg(STAT_NSECS, map_idx, &rsd);
f87027b9 784 if (total)
6859bc0e
CD
785 ratio = convert_unit_double(1000000000.0 * avg / total, &unit);
786
787 if (unit != ' ')
788 snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit);
6ca9a082 789 print_metric(config, ctxp, NULL, "%8.3f", unit_buf, ratio);
f87027b9 790 } else {
b18f3e36 791 num = 0;
f87027b9 792 }
b18f3e36
AK
793
794 if ((me = metricgroup__lookup(metric_events, evsel, false)) != NULL) {
795 struct metric_expr *mexp;
796
797 list_for_each_entry (mexp, &me->head, nd) {
798 if (num++ > 0)
6ca9a082 799 out->new_line(config, ctxp);
d0a3052f
IR
800 generic_metric(config, mexp->metric_expr, mexp->metric_threshold,
801 mexp->metric_events, mexp->metric_refs, evsel->name,
802 mexp->metric_name, mexp->metric_unit, mexp->runtime,
cc26ffaa 803 map_idx, out);
b18f3e36
AK
804 }
805 }
806 if (num == 0)
6ca9a082 807 print_metric(config, ctxp, NULL, NULL, NULL, 0);
f87027b9 808}