Merge tag 'for-linus-2021-01-24' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / tools / perf / util / stat-shadow.c
CommitLineData
b2441318 1// SPDX-License-Identifier: GPL-2.0
f87027b9
JO
2#include <stdio.h>
3#include "evsel.h"
4#include "stat.h"
5#include "color.h"
fb4605ba 6#include "pmu.h"
37932c18
AK
7#include "rblist.h"
8#include "evlist.h"
9#include "expr.h"
b18f3e36 10#include "metricgroup.h"
a1bf2305 11#include "cgroup.h"
d8f9da24 12#include <linux/zalloc.h>
f87027b9 13
44d49a60
AK
14/*
15 * AGGR_GLOBAL: Use CPU 0
16 * AGGR_SOCKET: Use first CPU of socket
db5742b6 17 * AGGR_DIE: Use first CPU of die
44d49a60
AK
18 * AGGR_CORE: Use first CPU of core
19 * AGGR_NONE: Use matching CPU
20 * AGGR_THREAD: Not supported?
21 */
f87027b9 22
8efb2df1 23struct runtime_stat rt_stat;
f87027b9
JO
24struct stats walltime_nsecs_stats;
25
37932c18
AK
26struct saved_value {
27 struct rb_node rb_node;
32dcd021 28 struct evsel *evsel;
49cd456a
JY
29 enum stat_type type;
30 int ctx;
37932c18 31 int cpu;
a1bf2305 32 struct cgroup *cgrp;
49cd456a 33 struct runtime_stat *stat;
37932c18 34 struct stats stats;
f01642e4
JY
35 u64 metric_total;
36 int metric_other;
37932c18
AK
37};
38
39static int saved_value_cmp(struct rb_node *rb_node, const void *entry)
40{
41 struct saved_value *a = container_of(rb_node,
42 struct saved_value,
43 rb_node);
44 const struct saved_value *b = entry;
45
37932c18
AK
46 if (a->cpu != b->cpu)
47 return a->cpu - b->cpu;
49cd456a
JY
48
49 /*
50 * Previously the rbtree was used to link generic metrics.
51 * The keys were evsel/cpu. Now the rbtree is extended to support
52 * per-thread shadow stats. For shadow stats case, the keys
53 * are cpu/type/ctx/stat (evsel is NULL). For generic metrics
54 * case, the keys are still evsel/cpu (type/ctx/stat are 0 or NULL).
55 */
56 if (a->type != b->type)
57 return a->type - b->type;
58
59 if (a->ctx != b->ctx)
60 return a->ctx - b->ctx;
61
a1bf2305
NK
62 if (a->cgrp != b->cgrp)
63 return (char *)a->cgrp < (char *)b->cgrp ? -1 : +1;
64
49cd456a
JY
65 if (a->evsel == NULL && b->evsel == NULL) {
66 if (a->stat == b->stat)
67 return 0;
68
69 if ((char *)a->stat < (char *)b->stat)
70 return -1;
71
72 return 1;
73 }
74
5e97665f
AK
75 if (a->evsel == b->evsel)
76 return 0;
77 if ((char *)a->evsel < (char *)b->evsel)
78 return -1;
79 return +1;
37932c18
AK
80}
81
82static struct rb_node *saved_value_new(struct rblist *rblist __maybe_unused,
83 const void *entry)
84{
85 struct saved_value *nd = malloc(sizeof(struct saved_value));
86
87 if (!nd)
88 return NULL;
89 memcpy(nd, entry, sizeof(struct saved_value));
90 return &nd->rb_node;
91}
92
b984aff7
JY
93static void saved_value_delete(struct rblist *rblist __maybe_unused,
94 struct rb_node *rb_node)
95{
96 struct saved_value *v;
97
98 BUG_ON(!rb_node);
99 v = container_of(rb_node, struct saved_value, rb_node);
100 free(v);
101}
102
32dcd021 103static struct saved_value *saved_value_lookup(struct evsel *evsel,
4e1a0963 104 int cpu,
1fcd0394
JY
105 bool create,
106 enum stat_type type,
107 int ctx,
a1bf2305
NK
108 struct runtime_stat *st,
109 struct cgroup *cgrp)
37932c18 110{
1fcd0394 111 struct rblist *rblist;
37932c18
AK
112 struct rb_node *nd;
113 struct saved_value dm = {
114 .cpu = cpu,
37932c18 115 .evsel = evsel,
1fcd0394
JY
116 .type = type,
117 .ctx = ctx,
118 .stat = st,
a1bf2305 119 .cgrp = cgrp,
37932c18 120 };
1fcd0394
JY
121
122 rblist = &st->value_list;
123
3ff1e718
NK
124 /* don't use context info for clock events */
125 if (type == STAT_NSECS)
126 dm.ctx = 0;
127
1fcd0394 128 nd = rblist__find(rblist, &dm);
37932c18
AK
129 if (nd)
130 return container_of(nd, struct saved_value, rb_node);
131 if (create) {
1fcd0394
JY
132 rblist__add_node(rblist, &dm);
133 nd = rblist__find(rblist, &dm);
37932c18
AK
134 if (nd)
135 return container_of(nd, struct saved_value, rb_node);
136 }
137 return NULL;
138}
139
8efb2df1
JY
140void runtime_stat__init(struct runtime_stat *st)
141{
142 struct rblist *rblist = &st->value_list;
143
144 rblist__init(rblist);
145 rblist->node_cmp = saved_value_cmp;
146 rblist->node_new = saved_value_new;
147 rblist->node_delete = saved_value_delete;
148}
149
150void runtime_stat__exit(struct runtime_stat *st)
151{
152 rblist__exit(&st->value_list);
153}
154
fb4605ba
AK
155void perf_stat__init_shadow_stats(void)
156{
8efb2df1 157 runtime_stat__init(&rt_stat);
fb4605ba
AK
158}
159
32dcd021 160static int evsel_context(struct evsel *evsel)
f87027b9
JO
161{
162 int ctx = 0;
163
1fc632ce 164 if (evsel->core.attr.exclude_kernel)
f87027b9 165 ctx |= CTX_BIT_KERNEL;
1fc632ce 166 if (evsel->core.attr.exclude_user)
f87027b9 167 ctx |= CTX_BIT_USER;
1fc632ce 168 if (evsel->core.attr.exclude_hv)
f87027b9 169 ctx |= CTX_BIT_HV;
1fc632ce 170 if (evsel->core.attr.exclude_host)
f87027b9 171 ctx |= CTX_BIT_HOST;
1fc632ce 172 if (evsel->core.attr.exclude_idle)
f87027b9
JO
173 ctx |= CTX_BIT_IDLE;
174
175 return ctx;
176}
177
6a1e2c5c 178static void reset_stat(struct runtime_stat *st)
f87027b9 179{
6a1e2c5c 180 struct rblist *rblist;
37932c18
AK
181 struct rb_node *pos, *next;
182
6a1e2c5c 183 rblist = &st->value_list;
ca227029 184 next = rb_first_cached(&rblist->entries);
37932c18
AK
185 while (next) {
186 pos = next;
187 next = rb_next(pos);
188 memset(&container_of(pos, struct saved_value, rb_node)->stats,
189 0,
190 sizeof(struct stats));
191 }
f87027b9
JO
192}
193
6a1e2c5c
JY
194void perf_stat__reset_shadow_stats(void)
195{
196 reset_stat(&rt_stat);
197 memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats));
198}
199
200void perf_stat__reset_shadow_per_stat(struct runtime_stat *st)
201{
202 reset_stat(st);
203}
204
3ff1e718
NK
205struct runtime_stat_data {
206 int ctx;
a1bf2305 207 struct cgroup *cgrp;
3ff1e718
NK
208};
209
1fcd0394
JY
210static void update_runtime_stat(struct runtime_stat *st,
211 enum stat_type type,
3ff1e718
NK
212 int cpu, u64 count,
213 struct runtime_stat_data *rsd)
1fcd0394 214{
3ff1e718 215 struct saved_value *v = saved_value_lookup(NULL, cpu, true, type,
a1bf2305 216 rsd->ctx, st, rsd->cgrp);
1fcd0394
JY
217
218 if (v)
219 update_stats(&v->stats, count);
220}
221
f87027b9
JO
222/*
223 * Update various tracking values we maintain to print
224 * more semantic information such as miss/hit ratios,
225 * instruction rates, etc:
226 */
32dcd021 227void perf_stat__update_shadow_stats(struct evsel *counter, u64 count,
1fcd0394 228 int cpu, struct runtime_stat *st)
f87027b9 229{
57ddf091 230 u64 count_ns = count;
f01642e4 231 struct saved_value *v;
3ff1e718
NK
232 struct runtime_stat_data rsd = {
233 .ctx = evsel_context(counter),
a1bf2305 234 .cgrp = counter->cgrp,
3ff1e718 235 };
f87027b9 236
54830dd0
JO
237 count *= counter->scale;
238
c754c382 239 if (evsel__is_clock(counter))
3ff1e718 240 update_runtime_stat(st, STAT_NSECS, cpu, count_ns, &rsd);
c754c382 241 else if (evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
3ff1e718 242 update_runtime_stat(st, STAT_CYCLES, cpu, count, &rsd);
f87027b9 243 else if (perf_stat_evsel__is(counter, CYCLES_IN_TX))
3ff1e718 244 update_runtime_stat(st, STAT_CYCLES_IN_TX, cpu, count, &rsd);
f87027b9 245 else if (perf_stat_evsel__is(counter, TRANSACTION_START))
3ff1e718 246 update_runtime_stat(st, STAT_TRANSACTION, cpu, count, &rsd);
f87027b9 247 else if (perf_stat_evsel__is(counter, ELISION_START))
3ff1e718 248 update_runtime_stat(st, STAT_ELISION, cpu, count, &rsd);
239bd47f 249 else if (perf_stat_evsel__is(counter, TOPDOWN_TOTAL_SLOTS))
1fcd0394 250 update_runtime_stat(st, STAT_TOPDOWN_TOTAL_SLOTS,
3ff1e718 251 cpu, count, &rsd);
239bd47f 252 else if (perf_stat_evsel__is(counter, TOPDOWN_SLOTS_ISSUED))
1fcd0394 253 update_runtime_stat(st, STAT_TOPDOWN_SLOTS_ISSUED,
3ff1e718 254 cpu, count, &rsd);
239bd47f 255 else if (perf_stat_evsel__is(counter, TOPDOWN_SLOTS_RETIRED))
1fcd0394 256 update_runtime_stat(st, STAT_TOPDOWN_SLOTS_RETIRED,
3ff1e718 257 cpu, count, &rsd);
239bd47f 258 else if (perf_stat_evsel__is(counter, TOPDOWN_FETCH_BUBBLES))
1fcd0394 259 update_runtime_stat(st, STAT_TOPDOWN_FETCH_BUBBLES,
3ff1e718 260 cpu, count, &rsd);
239bd47f 261 else if (perf_stat_evsel__is(counter, TOPDOWN_RECOVERY_BUBBLES))
1fcd0394 262 update_runtime_stat(st, STAT_TOPDOWN_RECOVERY_BUBBLES,
3ff1e718 263 cpu, count, &rsd);
55c36a9f
AK
264 else if (perf_stat_evsel__is(counter, TOPDOWN_RETIRING))
265 update_runtime_stat(st, STAT_TOPDOWN_RETIRING,
3ff1e718 266 cpu, count, &rsd);
55c36a9f
AK
267 else if (perf_stat_evsel__is(counter, TOPDOWN_BAD_SPEC))
268 update_runtime_stat(st, STAT_TOPDOWN_BAD_SPEC,
3ff1e718 269 cpu, count, &rsd);
55c36a9f
AK
270 else if (perf_stat_evsel__is(counter, TOPDOWN_FE_BOUND))
271 update_runtime_stat(st, STAT_TOPDOWN_FE_BOUND,
3ff1e718 272 cpu, count, &rsd);
55c36a9f
AK
273 else if (perf_stat_evsel__is(counter, TOPDOWN_BE_BOUND))
274 update_runtime_stat(st, STAT_TOPDOWN_BE_BOUND,
3ff1e718 275 cpu, count, &rsd);
c754c382 276 else if (evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND))
1fcd0394 277 update_runtime_stat(st, STAT_STALLED_CYCLES_FRONT,
3ff1e718 278 cpu, count, &rsd);
c754c382 279 else if (evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND))
1fcd0394 280 update_runtime_stat(st, STAT_STALLED_CYCLES_BACK,
3ff1e718 281 cpu, count, &rsd);
c754c382 282 else if (evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS))
3ff1e718 283 update_runtime_stat(st, STAT_BRANCHES, cpu, count, &rsd);
c754c382 284 else if (evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES))
3ff1e718 285 update_runtime_stat(st, STAT_CACHEREFS, cpu, count, &rsd);
c754c382 286 else if (evsel__match(counter, HW_CACHE, HW_CACHE_L1D))
3ff1e718 287 update_runtime_stat(st, STAT_L1_DCACHE, cpu, count, &rsd);
c754c382 288 else if (evsel__match(counter, HW_CACHE, HW_CACHE_L1I))
3ff1e718 289 update_runtime_stat(st, STAT_L1_ICACHE, cpu, count, &rsd);
c754c382 290 else if (evsel__match(counter, HW_CACHE, HW_CACHE_LL))
3ff1e718 291 update_runtime_stat(st, STAT_LL_CACHE, cpu, count, &rsd);
c754c382 292 else if (evsel__match(counter, HW_CACHE, HW_CACHE_DTLB))
3ff1e718 293 update_runtime_stat(st, STAT_DTLB_CACHE, cpu, count, &rsd);
c754c382 294 else if (evsel__match(counter, HW_CACHE, HW_CACHE_ITLB))
3ff1e718 295 update_runtime_stat(st, STAT_ITLB_CACHE, cpu, count, &rsd);
daefd0bc 296 else if (perf_stat_evsel__is(counter, SMI_NUM))
3ff1e718 297 update_runtime_stat(st, STAT_SMI_NUM, cpu, count, &rsd);
daefd0bc 298 else if (perf_stat_evsel__is(counter, APERF))
3ff1e718 299 update_runtime_stat(st, STAT_APERF, cpu, count, &rsd);
37932c18
AK
300
301 if (counter->collect_stat) {
a1bf2305
NK
302 v = saved_value_lookup(counter, cpu, true, STAT_NONE, 0, st,
303 rsd.cgrp);
54830dd0 304 update_stats(&v->stats, count);
f01642e4
JY
305 if (counter->metric_leader)
306 v->metric_total += count;
307 } else if (counter->metric_leader) {
308 v = saved_value_lookup(counter->metric_leader,
a1bf2305 309 cpu, true, STAT_NONE, 0, st, rsd.cgrp);
f01642e4
JY
310 v->metric_total += count;
311 v->metric_other++;
37932c18 312 }
f87027b9
JO
313}
314
315/* used for get_ratio_color() */
316enum grc_type {
317 GRC_STALLED_CYCLES_FE,
318 GRC_STALLED_CYCLES_BE,
319 GRC_CACHE_MISSES,
320 GRC_MAX_NR
321};
322
323static const char *get_ratio_color(enum grc_type type, double ratio)
324{
325 static const double grc_table[GRC_MAX_NR][3] = {
326 [GRC_STALLED_CYCLES_FE] = { 50.0, 30.0, 10.0 },
327 [GRC_STALLED_CYCLES_BE] = { 75.0, 50.0, 20.0 },
328 [GRC_CACHE_MISSES] = { 20.0, 10.0, 5.0 },
329 };
330 const char *color = PERF_COLOR_NORMAL;
331
332 if (ratio > grc_table[type][0])
333 color = PERF_COLOR_RED;
334 else if (ratio > grc_table[type][1])
335 color = PERF_COLOR_MAGENTA;
336 else if (ratio > grc_table[type][2])
337 color = PERF_COLOR_YELLOW;
338
339 return color;
340}
341
63503dba 342static struct evsel *perf_stat__find_event(struct evlist *evsel_list,
37932c18
AK
343 const char *name)
344{
32dcd021 345 struct evsel *c2;
37932c18
AK
346
347 evlist__for_each_entry (evsel_list, c2) {
145c407c 348 if (!strcasecmp(c2->name, name) && !c2->collect_stat)
37932c18
AK
349 return c2;
350 }
351 return NULL;
352}
353
354/* Mark MetricExpr target events and link events using them to them. */
63503dba 355void perf_stat__collect_metric_expr(struct evlist *evsel_list)
37932c18 356{
32dcd021 357 struct evsel *counter, *leader, **metric_events, *oc;
37932c18 358 bool found;
ded80bda
IR
359 struct expr_parse_ctx ctx;
360 struct hashmap_entry *cur;
361 size_t bkt;
37932c18 362 int i;
37932c18 363
ded80bda 364 expr__ctx_init(&ctx);
37932c18
AK
365 evlist__for_each_entry(evsel_list, counter) {
366 bool invalid = false;
367
368 leader = counter->leader;
369 if (!counter->metric_expr)
370 continue;
ded80bda
IR
371
372 expr__ctx_clear(&ctx);
37932c18
AK
373 metric_events = counter->metric_events;
374 if (!metric_events) {
ded80bda
IR
375 if (expr__find_other(counter->metric_expr,
376 counter->name,
377 &ctx, 1) < 0)
37932c18
AK
378 continue;
379
32dcd021 380 metric_events = calloc(sizeof(struct evsel *),
ded80bda
IR
381 hashmap__size(&ctx.ids) + 1);
382 if (!metric_events) {
383 expr__ctx_clear(&ctx);
37932c18 384 return;
ded80bda 385 }
37932c18
AK
386 counter->metric_events = metric_events;
387 }
388
ded80bda
IR
389 i = 0;
390 hashmap__for_each_entry((&ctx.ids), cur, bkt) {
391 const char *metric_name = (const char *)cur->key;
392
37932c18
AK
393 found = false;
394 if (leader) {
395 /* Search in group */
396 for_each_group_member (oc, leader) {
ded80bda
IR
397 if (!strcasecmp(oc->name,
398 metric_name) &&
145c407c 399 !oc->collect_stat) {
37932c18
AK
400 found = true;
401 break;
402 }
403 }
404 }
405 if (!found) {
406 /* Search ignoring groups */
ded80bda
IR
407 oc = perf_stat__find_event(evsel_list,
408 metric_name);
37932c18
AK
409 }
410 if (!oc) {
411 /* Deduping one is good enough to handle duplicated PMUs. */
412 static char *printed;
413
414 /*
415 * Adding events automatically would be difficult, because
416 * it would risk creating groups that are not schedulable.
417 * perf stat doesn't understand all the scheduling constraints
418 * of events. So we ask the user instead to add the missing
419 * events.
420 */
ded80bda
IR
421 if (!printed ||
422 strcasecmp(printed, metric_name)) {
37932c18
AK
423 fprintf(stderr,
424 "Add %s event to groups to get metric expression for %s\n",
ded80bda 425 metric_name,
37932c18 426 counter->name);
ded80bda 427 printed = strdup(metric_name);
37932c18
AK
428 }
429 invalid = true;
430 continue;
431 }
ded80bda 432 metric_events[i++] = oc;
37932c18
AK
433 oc->collect_stat = true;
434 }
435 metric_events[i] = NULL;
37932c18
AK
436 if (invalid) {
437 free(metric_events);
438 counter->metric_events = NULL;
439 counter->metric_expr = NULL;
440 }
441 }
ded80bda 442 expr__ctx_clear(&ctx);
37932c18
AK
443}
444
e0128b30 445static double runtime_stat_avg(struct runtime_stat *st,
3ff1e718
NK
446 enum stat_type type, int cpu,
447 struct runtime_stat_data *rsd)
e0128b30
JY
448{
449 struct saved_value *v;
450
a1bf2305 451 v = saved_value_lookup(NULL, cpu, false, type, rsd->ctx, st, rsd->cgrp);
e0128b30
JY
452 if (!v)
453 return 0.0;
454
455 return avg_stats(&v->stats);
456}
457
458static double runtime_stat_n(struct runtime_stat *st,
3ff1e718
NK
459 enum stat_type type, int cpu,
460 struct runtime_stat_data *rsd)
e0128b30
JY
461{
462 struct saved_value *v;
463
a1bf2305 464 v = saved_value_lookup(NULL, cpu, false, type, rsd->ctx, st, rsd->cgrp);
e0128b30
JY
465 if (!v)
466 return 0.0;
467
468 return v->stats.n;
469}
470
6ca9a082 471static void print_stalled_cycles_frontend(struct perf_stat_config *config,
3ff1e718 472 int cpu, double avg,
e0128b30 473 struct perf_stat_output_ctx *out,
3ff1e718
NK
474 struct runtime_stat *st,
475 struct runtime_stat_data *rsd)
f87027b9
JO
476{
477 double total, ratio = 0.0;
478 const char *color;
f87027b9 479
3ff1e718 480 total = runtime_stat_avg(st, STAT_CYCLES, cpu, rsd);
f87027b9
JO
481
482 if (total)
483 ratio = avg / total * 100.0;
484
485 color = get_ratio_color(GRC_STALLED_CYCLES_FE, ratio);
486
140aeadc 487 if (ratio)
6ca9a082 488 out->print_metric(config, out->ctx, color, "%7.2f%%", "frontend cycles idle",
140aeadc
AK
489 ratio);
490 else
6ca9a082 491 out->print_metric(config, out->ctx, NULL, NULL, "frontend cycles idle", 0);
f87027b9
JO
492}
493
6ca9a082 494static void print_stalled_cycles_backend(struct perf_stat_config *config,
3ff1e718 495 int cpu, double avg,
e0128b30 496 struct perf_stat_output_ctx *out,
3ff1e718
NK
497 struct runtime_stat *st,
498 struct runtime_stat_data *rsd)
f87027b9
JO
499{
500 double total, ratio = 0.0;
501 const char *color;
f87027b9 502
3ff1e718 503 total = runtime_stat_avg(st, STAT_CYCLES, cpu, rsd);
f87027b9
JO
504
505 if (total)
506 ratio = avg / total * 100.0;
507
508 color = get_ratio_color(GRC_STALLED_CYCLES_BE, ratio);
509
6ca9a082 510 out->print_metric(config, out->ctx, color, "%7.2f%%", "backend cycles idle", ratio);
f87027b9
JO
511}
512
6ca9a082 513static void print_branch_misses(struct perf_stat_config *config,
3ff1e718 514 int cpu, double avg,
e0128b30 515 struct perf_stat_output_ctx *out,
3ff1e718
NK
516 struct runtime_stat *st,
517 struct runtime_stat_data *rsd)
f87027b9
JO
518{
519 double total, ratio = 0.0;
520 const char *color;
f87027b9 521
3ff1e718 522 total = runtime_stat_avg(st, STAT_BRANCHES, cpu, rsd);
f87027b9
JO
523
524 if (total)
525 ratio = avg / total * 100.0;
526
527 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
528
6ca9a082 529 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all branches", ratio);
f87027b9
JO
530}
531
6ca9a082 532static void print_l1_dcache_misses(struct perf_stat_config *config,
3ff1e718 533 int cpu, double avg,
e0128b30 534 struct perf_stat_output_ctx *out,
3ff1e718
NK
535 struct runtime_stat *st,
536 struct runtime_stat_data *rsd)
f87027b9
JO
537{
538 double total, ratio = 0.0;
539 const char *color;
f87027b9 540
3ff1e718 541 total = runtime_stat_avg(st, STAT_L1_DCACHE, cpu, rsd);
f87027b9
JO
542
543 if (total)
544 ratio = avg / total * 100.0;
545
546 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
547
ce9c13f3 548 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all L1-dcache accesses", ratio);
f87027b9
JO
549}
550
6ca9a082 551static void print_l1_icache_misses(struct perf_stat_config *config,
3ff1e718 552 int cpu, double avg,
e0128b30 553 struct perf_stat_output_ctx *out,
3ff1e718
NK
554 struct runtime_stat *st,
555 struct runtime_stat_data *rsd)
f87027b9
JO
556{
557 double total, ratio = 0.0;
558 const char *color;
f87027b9 559
3ff1e718 560 total = runtime_stat_avg(st, STAT_L1_ICACHE, cpu, rsd);
f87027b9
JO
561
562 if (total)
563 ratio = avg / total * 100.0;
564
565 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
ce9c13f3 566 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all L1-icache accesses", ratio);
f87027b9
JO
567}
568
6ca9a082 569static void print_dtlb_cache_misses(struct perf_stat_config *config,
3ff1e718 570 int cpu, double avg,
e0128b30 571 struct perf_stat_output_ctx *out,
3ff1e718
NK
572 struct runtime_stat *st,
573 struct runtime_stat_data *rsd)
f87027b9
JO
574{
575 double total, ratio = 0.0;
576 const char *color;
f87027b9 577
3ff1e718 578 total = runtime_stat_avg(st, STAT_DTLB_CACHE, cpu, rsd);
f87027b9
JO
579
580 if (total)
581 ratio = avg / total * 100.0;
582
583 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
ce9c13f3 584 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all dTLB cache accesses", ratio);
f87027b9
JO
585}
586
6ca9a082 587static void print_itlb_cache_misses(struct perf_stat_config *config,
3ff1e718 588 int cpu, double avg,
e0128b30 589 struct perf_stat_output_ctx *out,
3ff1e718
NK
590 struct runtime_stat *st,
591 struct runtime_stat_data *rsd)
f87027b9
JO
592{
593 double total, ratio = 0.0;
594 const char *color;
f87027b9 595
3ff1e718 596 total = runtime_stat_avg(st, STAT_ITLB_CACHE, cpu, rsd);
f87027b9
JO
597
598 if (total)
599 ratio = avg / total * 100.0;
600
601 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
ce9c13f3 602 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all iTLB cache accesses", ratio);
f87027b9
JO
603}
604
6ca9a082 605static void print_ll_cache_misses(struct perf_stat_config *config,
3ff1e718 606 int cpu, double avg,
e0128b30 607 struct perf_stat_output_ctx *out,
3ff1e718
NK
608 struct runtime_stat *st,
609 struct runtime_stat_data *rsd)
f87027b9
JO
610{
611 double total, ratio = 0.0;
612 const char *color;
f87027b9 613
3ff1e718 614 total = runtime_stat_avg(st, STAT_LL_CACHE, cpu, rsd);
f87027b9
JO
615
616 if (total)
617 ratio = avg / total * 100.0;
618
619 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
ce9c13f3 620 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all LL-cache accesses", ratio);
f87027b9
JO
621}
622
239bd47f
AK
623/*
624 * High level "TopDown" CPU core pipe line bottleneck break down.
625 *
626 * Basic concept following
627 * Yasin, A Top Down Method for Performance analysis and Counter architecture
628 * ISPASS14
629 *
630 * The CPU pipeline is divided into 4 areas that can be bottlenecks:
631 *
632 * Frontend -> Backend -> Retiring
633 * BadSpeculation in addition means out of order execution that is thrown away
634 * (for example branch mispredictions)
635 * Frontend is instruction decoding.
636 * Backend is execution, like computation and accessing data in memory
637 * Retiring is good execution that is not directly bottlenecked
638 *
639 * The formulas are computed in slots.
640 * A slot is an entry in the pipeline each for the pipeline width
641 * (for example a 4-wide pipeline has 4 slots for each cycle)
642 *
643 * Formulas:
644 * BadSpeculation = ((SlotsIssued - SlotsRetired) + RecoveryBubbles) /
645 * TotalSlots
646 * Retiring = SlotsRetired / TotalSlots
647 * FrontendBound = FetchBubbles / TotalSlots
648 * BackendBound = 1.0 - BadSpeculation - Retiring - FrontendBound
649 *
650 * The kernel provides the mapping to the low level CPU events and any scaling
651 * needed for the CPU pipeline width, for example:
652 *
653 * TotalSlots = Cycles * 4
654 *
655 * The scaling factor is communicated in the sysfs unit.
656 *
657 * In some cases the CPU may not be able to measure all the formulas due to
658 * missing events. In this case multiple formulas are combined, as possible.
659 *
660 * Full TopDown supports more levels to sub-divide each area: for example
661 * BackendBound into computing bound and memory bound. For now we only
662 * support Level 1 TopDown.
663 */
664
665static double sanitize_val(double x)
666{
667 if (x < 0 && x >= -0.02)
668 return 0.0;
669 return x;
670}
671
3ff1e718
NK
672static double td_total_slots(int cpu, struct runtime_stat *st,
673 struct runtime_stat_data *rsd)
239bd47f 674{
3ff1e718 675 return runtime_stat_avg(st, STAT_TOPDOWN_TOTAL_SLOTS, cpu, rsd);
239bd47f
AK
676}
677
3ff1e718
NK
678static double td_bad_spec(int cpu, struct runtime_stat *st,
679 struct runtime_stat_data *rsd)
239bd47f
AK
680{
681 double bad_spec = 0;
682 double total_slots;
683 double total;
684
3ff1e718
NK
685 total = runtime_stat_avg(st, STAT_TOPDOWN_SLOTS_ISSUED, cpu, rsd) -
686 runtime_stat_avg(st, STAT_TOPDOWN_SLOTS_RETIRED, cpu, rsd) +
687 runtime_stat_avg(st, STAT_TOPDOWN_RECOVERY_BUBBLES, cpu, rsd);
e0128b30 688
3ff1e718 689 total_slots = td_total_slots(cpu, st, rsd);
239bd47f
AK
690 if (total_slots)
691 bad_spec = total / total_slots;
692 return sanitize_val(bad_spec);
693}
694
3ff1e718
NK
695static double td_retiring(int cpu, struct runtime_stat *st,
696 struct runtime_stat_data *rsd)
239bd47f
AK
697{
698 double retiring = 0;
3ff1e718 699 double total_slots = td_total_slots(cpu, st, rsd);
e0128b30 700 double ret_slots = runtime_stat_avg(st, STAT_TOPDOWN_SLOTS_RETIRED,
3ff1e718 701 cpu, rsd);
239bd47f
AK
702
703 if (total_slots)
704 retiring = ret_slots / total_slots;
705 return retiring;
706}
707
3ff1e718
NK
708static double td_fe_bound(int cpu, struct runtime_stat *st,
709 struct runtime_stat_data *rsd)
239bd47f
AK
710{
711 double fe_bound = 0;
3ff1e718 712 double total_slots = td_total_slots(cpu, st, rsd);
e0128b30 713 double fetch_bub = runtime_stat_avg(st, STAT_TOPDOWN_FETCH_BUBBLES,
3ff1e718 714 cpu, rsd);
239bd47f
AK
715
716 if (total_slots)
717 fe_bound = fetch_bub / total_slots;
718 return fe_bound;
719}
720
3ff1e718
NK
721static double td_be_bound(int cpu, struct runtime_stat *st,
722 struct runtime_stat_data *rsd)
239bd47f 723{
3ff1e718
NK
724 double sum = (td_fe_bound(cpu, st, rsd) +
725 td_bad_spec(cpu, st, rsd) +
726 td_retiring(cpu, st, rsd));
239bd47f
AK
727 if (sum == 0)
728 return 0;
729 return sanitize_val(1.0 - sum);
730}
731
55c36a9f
AK
732/*
733 * Kernel reports metrics multiplied with slots. To get back
734 * the ratios we need to recreate the sum.
735 */
736
3ff1e718
NK
737static double td_metric_ratio(int cpu, enum stat_type type,
738 struct runtime_stat *stat,
739 struct runtime_stat_data *rsd)
55c36a9f 740{
3ff1e718
NK
741 double sum = runtime_stat_avg(stat, STAT_TOPDOWN_RETIRING, cpu, rsd) +
742 runtime_stat_avg(stat, STAT_TOPDOWN_FE_BOUND, cpu, rsd) +
743 runtime_stat_avg(stat, STAT_TOPDOWN_BE_BOUND, cpu, rsd) +
744 runtime_stat_avg(stat, STAT_TOPDOWN_BAD_SPEC, cpu, rsd);
745 double d = runtime_stat_avg(stat, type, cpu, rsd);
55c36a9f
AK
746
747 if (sum)
748 return d / sum;
749 return 0;
750}
751
752/*
753 * ... but only if most of the values are actually available.
754 * We allow two missing.
755 */
756
3ff1e718
NK
757static bool full_td(int cpu, struct runtime_stat *stat,
758 struct runtime_stat_data *rsd)
55c36a9f
AK
759{
760 int c = 0;
761
3ff1e718 762 if (runtime_stat_avg(stat, STAT_TOPDOWN_RETIRING, cpu, rsd) > 0)
55c36a9f 763 c++;
3ff1e718 764 if (runtime_stat_avg(stat, STAT_TOPDOWN_BE_BOUND, cpu, rsd) > 0)
55c36a9f 765 c++;
3ff1e718 766 if (runtime_stat_avg(stat, STAT_TOPDOWN_FE_BOUND, cpu, rsd) > 0)
55c36a9f 767 c++;
3ff1e718 768 if (runtime_stat_avg(stat, STAT_TOPDOWN_BAD_SPEC, cpu, rsd) > 0)
55c36a9f
AK
769 c++;
770 return c >= 2;
771}
772
3ff1e718 773static void print_smi_cost(struct perf_stat_config *config, int cpu,
e0128b30 774 struct perf_stat_output_ctx *out,
3ff1e718
NK
775 struct runtime_stat *st,
776 struct runtime_stat_data *rsd)
daefd0bc
KL
777{
778 double smi_num, aperf, cycles, cost = 0.0;
daefd0bc
KL
779 const char *color = NULL;
780
3ff1e718
NK
781 smi_num = runtime_stat_avg(st, STAT_SMI_NUM, cpu, rsd);
782 aperf = runtime_stat_avg(st, STAT_APERF, cpu, rsd);
783 cycles = runtime_stat_avg(st, STAT_CYCLES, cpu, rsd);
daefd0bc
KL
784
785 if ((cycles == 0) || (aperf == 0))
786 return;
787
788 if (smi_num)
789 cost = (aperf - cycles) / aperf * 100.00;
790
791 if (cost > 10)
792 color = PERF_COLOR_RED;
6ca9a082
JO
793 out->print_metric(config, out->ctx, color, "%8.1f%%", "SMI cycles%", cost);
794 out->print_metric(config, out->ctx, NULL, "%4.0f", "SMI#", smi_num);
daefd0bc
KL
795}
796
2cfaa853 797static int prepare_metric(struct evsel **metric_events,
fc393839 798 struct metric_ref *metric_refs,
2cfaa853
JO
799 struct expr_parse_ctx *pctx,
800 int cpu,
801 struct runtime_stat *st)
bba49af8 802{
2cfaa853 803 double scale;
e3a94273 804 char *n, *pn;
fc393839 805 int i, j, ret;
bba49af8 806
2cfaa853 807 expr__ctx_init(pctx);
bba49af8
AK
808 for (i = 0; metric_events[i]; i++) {
809 struct saved_value *v;
fd48aad9 810 struct stats *stats;
f01642e4 811 u64 metric_total = 0;
fd48aad9
AK
812
813 if (!strcmp(metric_events[i]->name, "duration_time")) {
814 stats = &walltime_nsecs_stats;
815 scale = 1e-9;
816 } else {
1fcd0394 817 v = saved_value_lookup(metric_events[i], cpu, false,
a1bf2305
NK
818 STAT_NONE, 0, st,
819 metric_events[i]->cgrp);
fd48aad9
AK
820 if (!v)
821 break;
822 stats = &v->stats;
823 scale = 1.0;
f01642e4
JY
824
825 if (v->metric_other)
826 metric_total = v->metric_total;
fd48aad9 827 }
e3a94273
AK
828
829 n = strdup(metric_events[i]->name);
830 if (!n)
2cfaa853 831 return -ENOMEM;
e3a94273
AK
832 /*
833 * This display code with --no-merge adds [cpu] postfixes.
834 * These are not supported by the parser. Remove everything
835 * after the space.
836 */
837 pn = strchr(n, ' ');
838 if (pn)
839 *pn = 0;
f01642e4
JY
840
841 if (metric_total)
2c46f542 842 expr__add_id_val(pctx, n, metric_total);
f01642e4 843 else
2c46f542 844 expr__add_id_val(pctx, n, avg_stats(stats)*scale);
bba49af8 845 }
f01642e4 846
fc393839
JO
847 for (j = 0; metric_refs && metric_refs[j].metric_name; j++) {
848 ret = expr__add_ref(pctx, &metric_refs[j]);
849 if (ret)
850 return ret;
851 }
852
2cfaa853
JO
853 return i;
854}
855
856static void generic_metric(struct perf_stat_config *config,
857 const char *metric_expr,
858 struct evsel **metric_events,
fc393839 859 struct metric_ref *metric_refs,
2cfaa853
JO
860 char *name,
861 const char *metric_name,
862 const char *metric_unit,
863 int runtime,
864 int cpu,
865 struct perf_stat_output_ctx *out,
866 struct runtime_stat *st)
867{
868 print_metric_t print_metric = out->print_metric;
869 struct expr_parse_ctx pctx;
870 double ratio, scale;
871 int i;
872 void *ctxp = out->ctx;
873
fc393839 874 i = prepare_metric(metric_events, metric_refs, &pctx, cpu, st);
2cfaa853
JO
875 if (i < 0)
876 return;
877
bba49af8 878 if (!metric_events[i]) {
1e1a873d 879 if (expr__parse(&ratio, &pctx, metric_expr, runtime) == 0) {
287f2649
JY
880 char *unit;
881 char metric_bf[64];
882
883 if (metric_unit && metric_name) {
884 if (perf_pmu__convert_scale(metric_unit,
885 &unit, &scale) >= 0) {
886 ratio *= scale;
887 }
1e1a873d
KJ
888 if (strstr(metric_expr, "?"))
889 scnprintf(metric_bf, sizeof(metric_bf),
890 "%s %s_%d", unit, metric_name, runtime);
891 else
892 scnprintf(metric_bf, sizeof(metric_bf),
287f2649 893 "%s %s", unit, metric_name);
1e1a873d 894
287f2649
JY
895 print_metric(config, ctxp, NULL, "%8.1f",
896 metric_bf, ratio);
897 } else {
d4d5ca0b 898 print_metric(config, ctxp, NULL, "%8.2f",
287f2649
JY
899 metric_name ?
900 metric_name :
901 out->force_header ? name : "",
902 ratio);
903 }
904 } else {
6ca9a082 905 print_metric(config, ctxp, NULL, NULL,
4ed962eb
AK
906 out->force_header ?
907 (metric_name ? metric_name : name) : "", 0);
287f2649 908 }
8358f698
JY
909 } else {
910 print_metric(config, ctxp, NULL, NULL,
911 out->force_header ?
912 (metric_name ? metric_name : name) : "", 0);
913 }
e3a94273 914
ded80bda 915 expr__ctx_clear(&pctx);
bba49af8
AK
916}
917
6d432c4c
JO
918double test_generic_metric(struct metric_expr *mexp, int cpu, struct runtime_stat *st)
919{
920 struct expr_parse_ctx pctx;
437822bf 921 double ratio = 0.0;
6d432c4c 922
fc393839 923 if (prepare_metric(mexp->metric_events, mexp->metric_refs, &pctx, cpu, st) < 0)
437822bf 924 goto out;
6d432c4c
JO
925
926 if (expr__parse(&ratio, &pctx, mexp->metric_expr, 1))
437822bf 927 ratio = 0.0;
6d432c4c 928
437822bf
NK
929out:
930 expr__ctx_clear(&pctx);
6d432c4c
JO
931 return ratio;
932}
933
6ca9a082 934void perf_stat__print_shadow_stats(struct perf_stat_config *config,
32dcd021 935 struct evsel *evsel,
140aeadc 936 double avg, int cpu,
b18f3e36 937 struct perf_stat_output_ctx *out,
e0128b30
JY
938 struct rblist *metric_events,
939 struct runtime_stat *st)
f87027b9 940{
140aeadc
AK
941 void *ctxp = out->ctx;
942 print_metric_t print_metric = out->print_metric;
f87027b9 943 double total, ratio = 0.0, total2;
239bd47f 944 const char *color = NULL;
3ff1e718
NK
945 struct runtime_stat_data rsd = {
946 .ctx = evsel_context(evsel),
a1bf2305 947 .cgrp = evsel->cgrp,
3ff1e718 948 };
b18f3e36
AK
949 struct metric_event *me;
950 int num = 1;
f87027b9 951
c754c382 952 if (evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
3ff1e718 953 total = runtime_stat_avg(st, STAT_CYCLES, cpu, &rsd);
e0128b30 954
f87027b9
JO
955 if (total) {
956 ratio = avg / total;
6ca9a082 957 print_metric(config, ctxp, NULL, "%7.2f ",
140aeadc 958 "insn per cycle", ratio);
f87027b9 959 } else {
6ca9a082 960 print_metric(config, ctxp, NULL, NULL, "insn per cycle", 0);
f87027b9 961 }
e0128b30 962
3ff1e718 963 total = runtime_stat_avg(st, STAT_STALLED_CYCLES_FRONT, cpu, &rsd);
e0128b30
JY
964
965 total = max(total, runtime_stat_avg(st,
966 STAT_STALLED_CYCLES_BACK,
3ff1e718 967 cpu, &rsd));
f87027b9
JO
968
969 if (total && avg) {
6ca9a082 970 out->new_line(config, ctxp);
f87027b9 971 ratio = total / avg;
6ca9a082 972 print_metric(config, ctxp, NULL, "%7.2f ",
140aeadc
AK
973 "stalled cycles per insn",
974 ratio);
f87027b9 975 }
c754c382 976 } else if (evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES)) {
3ff1e718
NK
977 if (runtime_stat_n(st, STAT_BRANCHES, cpu, &rsd) != 0)
978 print_branch_misses(config, cpu, avg, out, st, &rsd);
140aeadc 979 else
6ca9a082 980 print_metric(config, ctxp, NULL, NULL, "of all branches", 0);
f87027b9 981 } else if (
1fc632ce
JO
982 evsel->core.attr.type == PERF_TYPE_HW_CACHE &&
983 evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_L1D |
f87027b9 984 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
140aeadc 985 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
e0128b30 986
3ff1e718
NK
987 if (runtime_stat_n(st, STAT_L1_DCACHE, cpu, &rsd) != 0)
988 print_l1_dcache_misses(config, cpu, avg, out, st, &rsd);
140aeadc 989 else
ce9c13f3 990 print_metric(config, ctxp, NULL, NULL, "of all L1-dcache accesses", 0);
f87027b9 991 } else if (
1fc632ce
JO
992 evsel->core.attr.type == PERF_TYPE_HW_CACHE &&
993 evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_L1I |
f87027b9 994 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
140aeadc 995 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
e0128b30 996
3ff1e718
NK
997 if (runtime_stat_n(st, STAT_L1_ICACHE, cpu, &rsd) != 0)
998 print_l1_icache_misses(config, cpu, avg, out, st, &rsd);
140aeadc 999 else
ce9c13f3 1000 print_metric(config, ctxp, NULL, NULL, "of all L1-icache accesses", 0);
f87027b9 1001 } else if (
1fc632ce
JO
1002 evsel->core.attr.type == PERF_TYPE_HW_CACHE &&
1003 evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_DTLB |
f87027b9 1004 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
140aeadc 1005 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
e0128b30 1006
3ff1e718
NK
1007 if (runtime_stat_n(st, STAT_DTLB_CACHE, cpu, &rsd) != 0)
1008 print_dtlb_cache_misses(config, cpu, avg, out, st, &rsd);
140aeadc 1009 else
ce9c13f3 1010 print_metric(config, ctxp, NULL, NULL, "of all dTLB cache accesses", 0);
f87027b9 1011 } else if (
1fc632ce
JO
1012 evsel->core.attr.type == PERF_TYPE_HW_CACHE &&
1013 evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_ITLB |
f87027b9 1014 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
140aeadc 1015 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
e0128b30 1016
3ff1e718
NK
1017 if (runtime_stat_n(st, STAT_ITLB_CACHE, cpu, &rsd) != 0)
1018 print_itlb_cache_misses(config, cpu, avg, out, st, &rsd);
140aeadc 1019 else
ce9c13f3 1020 print_metric(config, ctxp, NULL, NULL, "of all iTLB cache accesses", 0);
f87027b9 1021 } else if (
1fc632ce
JO
1022 evsel->core.attr.type == PERF_TYPE_HW_CACHE &&
1023 evsel->core.attr.config == ( PERF_COUNT_HW_CACHE_LL |
f87027b9 1024 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
140aeadc 1025 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
e0128b30 1026
3ff1e718
NK
1027 if (runtime_stat_n(st, STAT_LL_CACHE, cpu, &rsd) != 0)
1028 print_ll_cache_misses(config, cpu, avg, out, st, &rsd);
140aeadc 1029 else
ce9c13f3 1030 print_metric(config, ctxp, NULL, NULL, "of all LL-cache accesses", 0);
c754c382 1031 } else if (evsel__match(evsel, HARDWARE, HW_CACHE_MISSES)) {
3ff1e718 1032 total = runtime_stat_avg(st, STAT_CACHEREFS, cpu, &rsd);
f87027b9
JO
1033
1034 if (total)
1035 ratio = avg * 100 / total;
1036
3ff1e718 1037 if (runtime_stat_n(st, STAT_CACHEREFS, cpu, &rsd) != 0)
6ca9a082 1038 print_metric(config, ctxp, NULL, "%8.3f %%",
140aeadc
AK
1039 "of all cache refs", ratio);
1040 else
6ca9a082 1041 print_metric(config, ctxp, NULL, NULL, "of all cache refs", 0);
c754c382 1042 } else if (evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) {
3ff1e718 1043 print_stalled_cycles_frontend(config, cpu, avg, out, st, &rsd);
c754c382 1044 } else if (evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_BACKEND)) {
3ff1e718 1045 print_stalled_cycles_backend(config, cpu, avg, out, st, &rsd);
c754c382 1046 } else if (evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) {
3ff1e718 1047 total = runtime_stat_avg(st, STAT_NSECS, cpu, &rsd);
f87027b9
JO
1048
1049 if (total) {
1050 ratio = avg / total;
6ca9a082 1051 print_metric(config, ctxp, NULL, "%8.3f", "GHz", ratio);
f87027b9 1052 } else {
6ca9a082 1053 print_metric(config, ctxp, NULL, NULL, "Ghz", 0);
f87027b9
JO
1054 }
1055 } else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX)) {
3ff1e718 1056 total = runtime_stat_avg(st, STAT_CYCLES, cpu, &rsd);
e0128b30 1057
f87027b9 1058 if (total)
6ca9a082 1059 print_metric(config, ctxp, NULL,
140aeadc
AK
1060 "%7.2f%%", "transactional cycles",
1061 100.0 * (avg / total));
1062 else
6ca9a082 1063 print_metric(config, ctxp, NULL, NULL, "transactional cycles",
140aeadc 1064 0);
f87027b9 1065 } else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX_CP)) {
3ff1e718
NK
1066 total = runtime_stat_avg(st, STAT_CYCLES, cpu, &rsd);
1067 total2 = runtime_stat_avg(st, STAT_CYCLES_IN_TX, cpu, &rsd);
e0128b30 1068
f87027b9
JO
1069 if (total2 < avg)
1070 total2 = avg;
1071 if (total)
6ca9a082 1072 print_metric(config, ctxp, NULL, "%7.2f%%", "aborted cycles",
f87027b9 1073 100.0 * ((total2-avg) / total));
140aeadc 1074 else
6ca9a082 1075 print_metric(config, ctxp, NULL, NULL, "aborted cycles", 0);
140aeadc 1076 } else if (perf_stat_evsel__is(evsel, TRANSACTION_START)) {
3ff1e718 1077 total = runtime_stat_avg(st, STAT_CYCLES_IN_TX, cpu, &rsd);
f87027b9 1078
54976285 1079 if (avg)
f87027b9
JO
1080 ratio = total / avg;
1081
3ff1e718 1082 if (runtime_stat_n(st, STAT_CYCLES_IN_TX, cpu, &rsd) != 0)
6ca9a082 1083 print_metric(config, ctxp, NULL, "%8.0f",
140aeadc
AK
1084 "cycles / transaction", ratio);
1085 else
6ca9a082 1086 print_metric(config, ctxp, NULL, NULL, "cycles / transaction",
e0128b30 1087 0);
140aeadc 1088 } else if (perf_stat_evsel__is(evsel, ELISION_START)) {
3ff1e718 1089 total = runtime_stat_avg(st, STAT_CYCLES_IN_TX, cpu, &rsd);
f87027b9 1090
54976285 1091 if (avg)
f87027b9
JO
1092 ratio = total / avg;
1093
6ca9a082 1094 print_metric(config, ctxp, NULL, "%8.0f", "cycles / elision", ratio);
c754c382 1095 } else if (evsel__is_clock(evsel)) {
4579ecc8 1096 if ((ratio = avg_stats(&walltime_nsecs_stats)) != 0)
6ca9a082 1097 print_metric(config, ctxp, NULL, "%8.3f", "CPUs utilized",
0aa802a7 1098 avg / (ratio * evsel->scale));
4579ecc8 1099 else
6ca9a082 1100 print_metric(config, ctxp, NULL, NULL, "CPUs utilized", 0);
239bd47f 1101 } else if (perf_stat_evsel__is(evsel, TOPDOWN_FETCH_BUBBLES)) {
3ff1e718 1102 double fe_bound = td_fe_bound(cpu, st, &rsd);
239bd47f
AK
1103
1104 if (fe_bound > 0.2)
1105 color = PERF_COLOR_RED;
6ca9a082 1106 print_metric(config, ctxp, color, "%8.1f%%", "frontend bound",
239bd47f
AK
1107 fe_bound * 100.);
1108 } else if (perf_stat_evsel__is(evsel, TOPDOWN_SLOTS_RETIRED)) {
3ff1e718 1109 double retiring = td_retiring(cpu, st, &rsd);
239bd47f
AK
1110
1111 if (retiring > 0.7)
1112 color = PERF_COLOR_GREEN;
6ca9a082 1113 print_metric(config, ctxp, color, "%8.1f%%", "retiring",
239bd47f
AK
1114 retiring * 100.);
1115 } else if (perf_stat_evsel__is(evsel, TOPDOWN_RECOVERY_BUBBLES)) {
3ff1e718 1116 double bad_spec = td_bad_spec(cpu, st, &rsd);
239bd47f
AK
1117
1118 if (bad_spec > 0.1)
1119 color = PERF_COLOR_RED;
6ca9a082 1120 print_metric(config, ctxp, color, "%8.1f%%", "bad speculation",
239bd47f
AK
1121 bad_spec * 100.);
1122 } else if (perf_stat_evsel__is(evsel, TOPDOWN_SLOTS_ISSUED)) {
3ff1e718 1123 double be_bound = td_be_bound(cpu, st, &rsd);
239bd47f
AK
1124 const char *name = "backend bound";
1125 static int have_recovery_bubbles = -1;
1126
1127 /* In case the CPU does not support topdown-recovery-bubbles */
1128 if (have_recovery_bubbles < 0)
1129 have_recovery_bubbles = pmu_have_event("cpu",
1130 "topdown-recovery-bubbles");
1131 if (!have_recovery_bubbles)
1132 name = "backend bound/bad spec";
1133
1134 if (be_bound > 0.2)
1135 color = PERF_COLOR_RED;
3ff1e718 1136 if (td_total_slots(cpu, st, &rsd) > 0)
6ca9a082 1137 print_metric(config, ctxp, color, "%8.1f%%", name,
239bd47f
AK
1138 be_bound * 100.);
1139 else
6ca9a082 1140 print_metric(config, ctxp, NULL, NULL, name, 0);
55c36a9f 1141 } else if (perf_stat_evsel__is(evsel, TOPDOWN_RETIRING) &&
3ff1e718
NK
1142 full_td(cpu, st, &rsd)) {
1143 double retiring = td_metric_ratio(cpu,
1144 STAT_TOPDOWN_RETIRING, st,
1145 &rsd);
55c36a9f
AK
1146 if (retiring > 0.7)
1147 color = PERF_COLOR_GREEN;
1148 print_metric(config, ctxp, color, "%8.1f%%", "retiring",
1149 retiring * 100.);
1150 } else if (perf_stat_evsel__is(evsel, TOPDOWN_FE_BOUND) &&
3ff1e718
NK
1151 full_td(cpu, st, &rsd)) {
1152 double fe_bound = td_metric_ratio(cpu,
1153 STAT_TOPDOWN_FE_BOUND, st,
1154 &rsd);
55c36a9f
AK
1155 if (fe_bound > 0.2)
1156 color = PERF_COLOR_RED;
1157 print_metric(config, ctxp, color, "%8.1f%%", "frontend bound",
1158 fe_bound * 100.);
1159 } else if (perf_stat_evsel__is(evsel, TOPDOWN_BE_BOUND) &&
3ff1e718
NK
1160 full_td(cpu, st, &rsd)) {
1161 double be_bound = td_metric_ratio(cpu,
1162 STAT_TOPDOWN_BE_BOUND, st,
1163 &rsd);
55c36a9f
AK
1164 if (be_bound > 0.2)
1165 color = PERF_COLOR_RED;
1166 print_metric(config, ctxp, color, "%8.1f%%", "backend bound",
1167 be_bound * 100.);
1168 } else if (perf_stat_evsel__is(evsel, TOPDOWN_BAD_SPEC) &&
3ff1e718
NK
1169 full_td(cpu, st, &rsd)) {
1170 double bad_spec = td_metric_ratio(cpu,
1171 STAT_TOPDOWN_BAD_SPEC, st,
1172 &rsd);
55c36a9f
AK
1173 if (bad_spec > 0.1)
1174 color = PERF_COLOR_RED;
1175 print_metric(config, ctxp, color, "%8.1f%%", "bad speculation",
1176 bad_spec * 100.);
37932c18 1177 } else if (evsel->metric_expr) {
fc393839
JO
1178 generic_metric(config, evsel->metric_expr, evsel->metric_events, NULL,
1179 evsel->name, evsel->metric_name, NULL, 1, cpu, out, st);
3ff1e718 1180 } else if (runtime_stat_n(st, STAT_NSECS, cpu, &rsd) != 0) {
f87027b9 1181 char unit = 'M';
140aeadc 1182 char unit_buf[10];
f87027b9 1183
3ff1e718 1184 total = runtime_stat_avg(st, STAT_NSECS, cpu, &rsd);
f87027b9
JO
1185
1186 if (total)
1187 ratio = 1000.0 * avg / total;
1188 if (ratio < 0.001) {
1189 ratio *= 1000;
1190 unit = 'K';
1191 }
140aeadc 1192 snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit);
6ca9a082 1193 print_metric(config, ctxp, NULL, "%8.3f", unit_buf, ratio);
daefd0bc 1194 } else if (perf_stat_evsel__is(evsel, SMI_NUM)) {
3ff1e718 1195 print_smi_cost(config, cpu, out, st, &rsd);
f87027b9 1196 } else {
b18f3e36 1197 num = 0;
f87027b9 1198 }
b18f3e36
AK
1199
1200 if ((me = metricgroup__lookup(metric_events, evsel, false)) != NULL) {
1201 struct metric_expr *mexp;
1202
1203 list_for_each_entry (mexp, &me->head, nd) {
1204 if (num++ > 0)
6ca9a082
JO
1205 out->new_line(config, ctxp);
1206 generic_metric(config, mexp->metric_expr, mexp->metric_events,
fc393839 1207 mexp->metric_refs, evsel->name, mexp->metric_name,
5f09ca5a 1208 mexp->metric_unit, mexp->runtime, cpu, out, st);
b18f3e36
AK
1209 }
1210 }
1211 if (num == 0)
6ca9a082 1212 print_metric(config, ctxp, NULL, NULL, NULL, 0);
f87027b9 1213}