blob: 8ad32763cffff718751f374e2eeb4f07a43bad6f [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001// SPDX-License-Identifier: GPL-2.0
Jiri Olsaf87027b2015-06-03 16:25:59 +02002#include <stdio.h>
3#include "evsel.h"
4#include "stat.h"
5#include "color.h"
Andi Kleenfb4605b2016-03-01 10:57:52 -08006#include "pmu.h"
Andi Kleen37932c12017-03-20 13:17:08 -07007#include "rblist.h"
8#include "evlist.h"
9#include "expr.h"
Andi Kleenb18f3e32017-08-31 12:40:31 -070010#include "metricgroup.h"
Jiri Olsaf87027b2015-06-03 16:25:59 +020011
Andi Kleen44d49a62016-02-29 14:36:22 -080012/*
13 * AGGR_GLOBAL: Use CPU 0
14 * AGGR_SOCKET: Use first CPU of socket
15 * AGGR_CORE: Use first CPU of core
16 * AGGR_NONE: Use matching CPU
17 * AGGR_THREAD: Not supported?
18 */
Andi Kleenfb4605b2016-03-01 10:57:52 -080019static bool have_frontend_stalled;
Jiri Olsaf87027b2015-06-03 16:25:59 +020020
Jin Yao8efb2df2017-12-05 22:03:03 +080021struct runtime_stat rt_stat;
Jiri Olsaf87027b2015-06-03 16:25:59 +020022struct stats walltime_nsecs_stats;
23
Andi Kleen37932c12017-03-20 13:17:08 -070024struct saved_value {
25 struct rb_node rb_node;
26 struct perf_evsel *evsel;
Jin Yao49cd4562017-12-05 22:03:02 +080027 enum stat_type type;
28 int ctx;
Andi Kleen37932c12017-03-20 13:17:08 -070029 int cpu;
Jin Yao49cd4562017-12-05 22:03:02 +080030 struct runtime_stat *stat;
Andi Kleen37932c12017-03-20 13:17:08 -070031 struct stats stats;
32};
33
34static int saved_value_cmp(struct rb_node *rb_node, const void *entry)
35{
36 struct saved_value *a = container_of(rb_node,
37 struct saved_value,
38 rb_node);
39 const struct saved_value *b = entry;
40
Andi Kleen37932c12017-03-20 13:17:08 -070041 if (a->cpu != b->cpu)
42 return a->cpu - b->cpu;
Jin Yao49cd4562017-12-05 22:03:02 +080043
44 /*
45 * Previously the rbtree was used to link generic metrics.
46 * The keys were evsel/cpu. Now the rbtree is extended to support
47 * per-thread shadow stats. For shadow stats case, the keys
48 * are cpu/type/ctx/stat (evsel is NULL). For generic metrics
49 * case, the keys are still evsel/cpu (type/ctx/stat are 0 or NULL).
50 */
51 if (a->type != b->type)
52 return a->type - b->type;
53
54 if (a->ctx != b->ctx)
55 return a->ctx - b->ctx;
56
57 if (a->evsel == NULL && b->evsel == NULL) {
58 if (a->stat == b->stat)
59 return 0;
60
61 if ((char *)a->stat < (char *)b->stat)
62 return -1;
63
64 return 1;
65 }
66
Andi Kleen5e976652017-07-24 16:40:03 -070067 if (a->evsel == b->evsel)
68 return 0;
69 if ((char *)a->evsel < (char *)b->evsel)
70 return -1;
71 return +1;
Andi Kleen37932c12017-03-20 13:17:08 -070072}
73
74static struct rb_node *saved_value_new(struct rblist *rblist __maybe_unused,
75 const void *entry)
76{
77 struct saved_value *nd = malloc(sizeof(struct saved_value));
78
79 if (!nd)
80 return NULL;
81 memcpy(nd, entry, sizeof(struct saved_value));
82 return &nd->rb_node;
83}
84
Jin Yaob984aff2017-12-01 18:57:28 +080085static void saved_value_delete(struct rblist *rblist __maybe_unused,
86 struct rb_node *rb_node)
87{
88 struct saved_value *v;
89
90 BUG_ON(!rb_node);
91 v = container_of(rb_node, struct saved_value, rb_node);
92 free(v);
93}
94
Andi Kleen37932c12017-03-20 13:17:08 -070095static struct saved_value *saved_value_lookup(struct perf_evsel *evsel,
Andi Kleen4e1a0962017-08-31 12:40:33 -070096 int cpu,
Jin Yao1fcd0392017-12-05 22:03:04 +080097 bool create,
98 enum stat_type type,
99 int ctx,
100 struct runtime_stat *st)
Andi Kleen37932c12017-03-20 13:17:08 -0700101{
Jin Yao1fcd0392017-12-05 22:03:04 +0800102 struct rblist *rblist;
Andi Kleen37932c12017-03-20 13:17:08 -0700103 struct rb_node *nd;
104 struct saved_value dm = {
105 .cpu = cpu,
Andi Kleen37932c12017-03-20 13:17:08 -0700106 .evsel = evsel,
Jin Yao1fcd0392017-12-05 22:03:04 +0800107 .type = type,
108 .ctx = ctx,
109 .stat = st,
Andi Kleen37932c12017-03-20 13:17:08 -0700110 };
Jin Yao1fcd0392017-12-05 22:03:04 +0800111
112 rblist = &st->value_list;
113
114 nd = rblist__find(rblist, &dm);
Andi Kleen37932c12017-03-20 13:17:08 -0700115 if (nd)
116 return container_of(nd, struct saved_value, rb_node);
117 if (create) {
Jin Yao1fcd0392017-12-05 22:03:04 +0800118 rblist__add_node(rblist, &dm);
119 nd = rblist__find(rblist, &dm);
Andi Kleen37932c12017-03-20 13:17:08 -0700120 if (nd)
121 return container_of(nd, struct saved_value, rb_node);
122 }
123 return NULL;
124}
125
Jin Yao8efb2df2017-12-05 22:03:03 +0800126void runtime_stat__init(struct runtime_stat *st)
127{
128 struct rblist *rblist = &st->value_list;
129
130 rblist__init(rblist);
131 rblist->node_cmp = saved_value_cmp;
132 rblist->node_new = saved_value_new;
133 rblist->node_delete = saved_value_delete;
134}
135
136void runtime_stat__exit(struct runtime_stat *st)
137{
138 rblist__exit(&st->value_list);
139}
140
Andi Kleenfb4605b2016-03-01 10:57:52 -0800141void perf_stat__init_shadow_stats(void)
142{
143 have_frontend_stalled = pmu_have_event("cpu", "stalled-cycles-frontend");
Jin Yao8efb2df2017-12-05 22:03:03 +0800144 runtime_stat__init(&rt_stat);
Andi Kleenfb4605b2016-03-01 10:57:52 -0800145}
146
Jiri Olsaf87027b2015-06-03 16:25:59 +0200147static int evsel_context(struct perf_evsel *evsel)
148{
149 int ctx = 0;
150
151 if (evsel->attr.exclude_kernel)
152 ctx |= CTX_BIT_KERNEL;
153 if (evsel->attr.exclude_user)
154 ctx |= CTX_BIT_USER;
155 if (evsel->attr.exclude_hv)
156 ctx |= CTX_BIT_HV;
157 if (evsel->attr.exclude_host)
158 ctx |= CTX_BIT_HOST;
159 if (evsel->attr.exclude_idle)
160 ctx |= CTX_BIT_IDLE;
161
162 return ctx;
163}
164
Jin Yao6a1e2c52017-12-05 22:03:06 +0800165static void reset_stat(struct runtime_stat *st)
Jiri Olsaf87027b2015-06-03 16:25:59 +0200166{
Jin Yao6a1e2c52017-12-05 22:03:06 +0800167 struct rblist *rblist;
Andi Kleen37932c12017-03-20 13:17:08 -0700168 struct rb_node *pos, *next;
169
Jin Yao6a1e2c52017-12-05 22:03:06 +0800170 rblist = &st->value_list;
171 next = rb_first(&rblist->entries);
Andi Kleen37932c12017-03-20 13:17:08 -0700172 while (next) {
173 pos = next;
174 next = rb_next(pos);
175 memset(&container_of(pos, struct saved_value, rb_node)->stats,
176 0,
177 sizeof(struct stats));
178 }
Jiri Olsaf87027b2015-06-03 16:25:59 +0200179}
180
Jin Yao6a1e2c52017-12-05 22:03:06 +0800181void perf_stat__reset_shadow_stats(void)
182{
183 reset_stat(&rt_stat);
184 memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats));
185}
186
187void perf_stat__reset_shadow_per_stat(struct runtime_stat *st)
188{
189 reset_stat(st);
190}
191
Jin Yao1fcd0392017-12-05 22:03:04 +0800192static void update_runtime_stat(struct runtime_stat *st,
193 enum stat_type type,
194 int ctx, int cpu, u64 count)
195{
196 struct saved_value *v = saved_value_lookup(NULL, cpu, true,
197 type, ctx, st);
198
199 if (v)
200 update_stats(&v->stats, count);
201}
202
Jiri Olsaf87027b2015-06-03 16:25:59 +0200203/*
204 * Update various tracking values we maintain to print
205 * more semantic information such as miss/hit ratios,
206 * instruction rates, etc:
207 */
Jiri Olsa54830dd2017-01-23 22:42:56 +0100208void perf_stat__update_shadow_stats(struct perf_evsel *counter, u64 count,
Jin Yao1fcd0392017-12-05 22:03:04 +0800209 int cpu, struct runtime_stat *st)
Jiri Olsaf87027b2015-06-03 16:25:59 +0200210{
211 int ctx = evsel_context(counter);
212
Jiri Olsa54830dd2017-01-23 22:42:56 +0100213 count *= counter->scale;
214
Namhyung Kimdaf4f472016-05-13 15:01:02 +0900215 if (perf_evsel__match(counter, SOFTWARE, SW_TASK_CLOCK) ||
216 perf_evsel__match(counter, SOFTWARE, SW_CPU_CLOCK))
Jin Yao1fcd0392017-12-05 22:03:04 +0800217 update_runtime_stat(st, STAT_NSECS, 0, cpu, count);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200218 else if (perf_evsel__match(counter, HARDWARE, HW_CPU_CYCLES))
Jin Yao1fcd0392017-12-05 22:03:04 +0800219 update_runtime_stat(st, STAT_CYCLES, ctx, cpu, count);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200220 else if (perf_stat_evsel__is(counter, CYCLES_IN_TX))
Jin Yao1fcd0392017-12-05 22:03:04 +0800221 update_runtime_stat(st, STAT_CYCLES_IN_TX, ctx, cpu, count);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200222 else if (perf_stat_evsel__is(counter, TRANSACTION_START))
Jin Yao1fcd0392017-12-05 22:03:04 +0800223 update_runtime_stat(st, STAT_TRANSACTION, ctx, cpu, count);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200224 else if (perf_stat_evsel__is(counter, ELISION_START))
Jin Yao1fcd0392017-12-05 22:03:04 +0800225 update_runtime_stat(st, STAT_ELISION, ctx, cpu, count);
Andi Kleen239bd472016-05-24 12:52:37 -0700226 else if (perf_stat_evsel__is(counter, TOPDOWN_TOTAL_SLOTS))
Jin Yao1fcd0392017-12-05 22:03:04 +0800227 update_runtime_stat(st, STAT_TOPDOWN_TOTAL_SLOTS,
228 ctx, cpu, count);
Andi Kleen239bd472016-05-24 12:52:37 -0700229 else if (perf_stat_evsel__is(counter, TOPDOWN_SLOTS_ISSUED))
Jin Yao1fcd0392017-12-05 22:03:04 +0800230 update_runtime_stat(st, STAT_TOPDOWN_SLOTS_ISSUED,
231 ctx, cpu, count);
Andi Kleen239bd472016-05-24 12:52:37 -0700232 else if (perf_stat_evsel__is(counter, TOPDOWN_SLOTS_RETIRED))
Jin Yao1fcd0392017-12-05 22:03:04 +0800233 update_runtime_stat(st, STAT_TOPDOWN_SLOTS_RETIRED,
234 ctx, cpu, count);
Andi Kleen239bd472016-05-24 12:52:37 -0700235 else if (perf_stat_evsel__is(counter, TOPDOWN_FETCH_BUBBLES))
Jin Yao1fcd0392017-12-05 22:03:04 +0800236 update_runtime_stat(st, STAT_TOPDOWN_FETCH_BUBBLES,
237 ctx, cpu, count);
Andi Kleen239bd472016-05-24 12:52:37 -0700238 else if (perf_stat_evsel__is(counter, TOPDOWN_RECOVERY_BUBBLES))
Jin Yao1fcd0392017-12-05 22:03:04 +0800239 update_runtime_stat(st, STAT_TOPDOWN_RECOVERY_BUBBLES,
240 ctx, cpu, count);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200241 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_FRONTEND))
Jin Yao1fcd0392017-12-05 22:03:04 +0800242 update_runtime_stat(st, STAT_STALLED_CYCLES_FRONT,
243 ctx, cpu, count);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200244 else if (perf_evsel__match(counter, HARDWARE, HW_STALLED_CYCLES_BACKEND))
Jin Yao1fcd0392017-12-05 22:03:04 +0800245 update_runtime_stat(st, STAT_STALLED_CYCLES_BACK,
246 ctx, cpu, count);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200247 else if (perf_evsel__match(counter, HARDWARE, HW_BRANCH_INSTRUCTIONS))
Jin Yao1fcd0392017-12-05 22:03:04 +0800248 update_runtime_stat(st, STAT_BRANCHES, ctx, cpu, count);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200249 else if (perf_evsel__match(counter, HARDWARE, HW_CACHE_REFERENCES))
Jin Yao1fcd0392017-12-05 22:03:04 +0800250 update_runtime_stat(st, STAT_CACHEREFS, ctx, cpu, count);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200251 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1D))
Jin Yao1fcd0392017-12-05 22:03:04 +0800252 update_runtime_stat(st, STAT_L1_DCACHE, ctx, cpu, count);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200253 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_L1I))
Jin Yao1fcd0392017-12-05 22:03:04 +0800254 update_runtime_stat(st, STAT_L1_ICACHE, ctx, cpu, count);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200255 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_LL))
Jin Yao1fcd0392017-12-05 22:03:04 +0800256 update_runtime_stat(st, STAT_LL_CACHE, ctx, cpu, count);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200257 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_DTLB))
Jin Yao1fcd0392017-12-05 22:03:04 +0800258 update_runtime_stat(st, STAT_DTLB_CACHE, ctx, cpu, count);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200259 else if (perf_evsel__match(counter, HW_CACHE, HW_CACHE_ITLB))
Jin Yao1fcd0392017-12-05 22:03:04 +0800260 update_runtime_stat(st, STAT_ITLB_CACHE, ctx, cpu, count);
Kan Liangdaefd0b2017-05-26 12:05:38 -0700261 else if (perf_stat_evsel__is(counter, SMI_NUM))
Jin Yao1fcd0392017-12-05 22:03:04 +0800262 update_runtime_stat(st, STAT_SMI_NUM, ctx, cpu, count);
Kan Liangdaefd0b2017-05-26 12:05:38 -0700263 else if (perf_stat_evsel__is(counter, APERF))
Jin Yao1fcd0392017-12-05 22:03:04 +0800264 update_runtime_stat(st, STAT_APERF, ctx, cpu, count);
Andi Kleen37932c12017-03-20 13:17:08 -0700265
266 if (counter->collect_stat) {
Jin Yao1fcd0392017-12-05 22:03:04 +0800267 struct saved_value *v = saved_value_lookup(counter, cpu, true,
268 STAT_NONE, 0, st);
Jiri Olsa54830dd2017-01-23 22:42:56 +0100269 update_stats(&v->stats, count);
Andi Kleen37932c12017-03-20 13:17:08 -0700270 }
Jiri Olsaf87027b2015-06-03 16:25:59 +0200271}
272
273/* used for get_ratio_color() */
274enum grc_type {
275 GRC_STALLED_CYCLES_FE,
276 GRC_STALLED_CYCLES_BE,
277 GRC_CACHE_MISSES,
278 GRC_MAX_NR
279};
280
281static const char *get_ratio_color(enum grc_type type, double ratio)
282{
283 static const double grc_table[GRC_MAX_NR][3] = {
284 [GRC_STALLED_CYCLES_FE] = { 50.0, 30.0, 10.0 },
285 [GRC_STALLED_CYCLES_BE] = { 75.0, 50.0, 20.0 },
286 [GRC_CACHE_MISSES] = { 20.0, 10.0, 5.0 },
287 };
288 const char *color = PERF_COLOR_NORMAL;
289
290 if (ratio > grc_table[type][0])
291 color = PERF_COLOR_RED;
292 else if (ratio > grc_table[type][1])
293 color = PERF_COLOR_MAGENTA;
294 else if (ratio > grc_table[type][2])
295 color = PERF_COLOR_YELLOW;
296
297 return color;
298}
299
Andi Kleen37932c12017-03-20 13:17:08 -0700300static struct perf_evsel *perf_stat__find_event(struct perf_evlist *evsel_list,
301 const char *name)
302{
303 struct perf_evsel *c2;
304
305 evlist__for_each_entry (evsel_list, c2) {
306 if (!strcasecmp(c2->name, name))
307 return c2;
308 }
309 return NULL;
310}
311
312/* Mark MetricExpr target events and link events using them to them. */
313void perf_stat__collect_metric_expr(struct perf_evlist *evsel_list)
314{
315 struct perf_evsel *counter, *leader, **metric_events, *oc;
316 bool found;
317 const char **metric_names;
318 int i;
319 int num_metric_names;
320
321 evlist__for_each_entry(evsel_list, counter) {
322 bool invalid = false;
323
324 leader = counter->leader;
325 if (!counter->metric_expr)
326 continue;
327 metric_events = counter->metric_events;
328 if (!metric_events) {
329 if (expr__find_other(counter->metric_expr, counter->name,
330 &metric_names, &num_metric_names) < 0)
331 continue;
332
333 metric_events = calloc(sizeof(struct perf_evsel *),
334 num_metric_names + 1);
335 if (!metric_events)
336 return;
337 counter->metric_events = metric_events;
338 }
339
340 for (i = 0; i < num_metric_names; i++) {
341 found = false;
342 if (leader) {
343 /* Search in group */
344 for_each_group_member (oc, leader) {
345 if (!strcasecmp(oc->name, metric_names[i])) {
346 found = true;
347 break;
348 }
349 }
350 }
351 if (!found) {
352 /* Search ignoring groups */
353 oc = perf_stat__find_event(evsel_list, metric_names[i]);
354 }
355 if (!oc) {
356 /* Deduping one is good enough to handle duplicated PMUs. */
357 static char *printed;
358
359 /*
360 * Adding events automatically would be difficult, because
361 * it would risk creating groups that are not schedulable.
362 * perf stat doesn't understand all the scheduling constraints
363 * of events. So we ask the user instead to add the missing
364 * events.
365 */
366 if (!printed || strcasecmp(printed, metric_names[i])) {
367 fprintf(stderr,
368 "Add %s event to groups to get metric expression for %s\n",
369 metric_names[i],
370 counter->name);
371 printed = strdup(metric_names[i]);
372 }
373 invalid = true;
374 continue;
375 }
376 metric_events[i] = oc;
377 oc->collect_stat = true;
378 }
379 metric_events[i] = NULL;
380 free(metric_names);
381 if (invalid) {
382 free(metric_events);
383 counter->metric_events = NULL;
384 counter->metric_expr = NULL;
385 }
386 }
387}
388
Jin Yaoe0128b32017-12-05 22:03:05 +0800389static double runtime_stat_avg(struct runtime_stat *st,
390 enum stat_type type, int ctx, int cpu)
391{
392 struct saved_value *v;
393
394 v = saved_value_lookup(NULL, cpu, false, type, ctx, st);
395 if (!v)
396 return 0.0;
397
398 return avg_stats(&v->stats);
399}
400
401static double runtime_stat_n(struct runtime_stat *st,
402 enum stat_type type, int ctx, int cpu)
403{
404 struct saved_value *v;
405
406 v = saved_value_lookup(NULL, cpu, false, type, ctx, st);
407 if (!v)
408 return 0.0;
409
410 return v->stats.n;
411}
412
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200413static void print_stalled_cycles_frontend(struct perf_stat_config *config,
414 int cpu,
Arnaldo Carvalho de Melob8f8eb82016-03-22 13:09:37 -0300415 struct perf_evsel *evsel, double avg,
Jin Yaoe0128b32017-12-05 22:03:05 +0800416 struct perf_stat_output_ctx *out,
417 struct runtime_stat *st)
Jiri Olsaf87027b2015-06-03 16:25:59 +0200418{
419 double total, ratio = 0.0;
420 const char *color;
421 int ctx = evsel_context(evsel);
422
Jin Yaoe0128b32017-12-05 22:03:05 +0800423 total = runtime_stat_avg(st, STAT_CYCLES, ctx, cpu);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200424
425 if (total)
426 ratio = avg / total * 100.0;
427
428 color = get_ratio_color(GRC_STALLED_CYCLES_FE, ratio);
429
Andi Kleen140aead2016-01-30 09:06:49 -0800430 if (ratio)
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200431 out->print_metric(config, out->ctx, color, "%7.2f%%", "frontend cycles idle",
Andi Kleen140aead2016-01-30 09:06:49 -0800432 ratio);
433 else
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200434 out->print_metric(config, out->ctx, NULL, NULL, "frontend cycles idle", 0);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200435}
436
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200437static void print_stalled_cycles_backend(struct perf_stat_config *config,
438 int cpu,
Arnaldo Carvalho de Melob8f8eb82016-03-22 13:09:37 -0300439 struct perf_evsel *evsel, double avg,
Jin Yaoe0128b32017-12-05 22:03:05 +0800440 struct perf_stat_output_ctx *out,
441 struct runtime_stat *st)
Jiri Olsaf87027b2015-06-03 16:25:59 +0200442{
443 double total, ratio = 0.0;
444 const char *color;
445 int ctx = evsel_context(evsel);
446
Jin Yaoe0128b32017-12-05 22:03:05 +0800447 total = runtime_stat_avg(st, STAT_CYCLES, ctx, cpu);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200448
449 if (total)
450 ratio = avg / total * 100.0;
451
452 color = get_ratio_color(GRC_STALLED_CYCLES_BE, ratio);
453
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200454 out->print_metric(config, out->ctx, color, "%7.2f%%", "backend cycles idle", ratio);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200455}
456
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200457static void print_branch_misses(struct perf_stat_config *config,
458 int cpu,
Arnaldo Carvalho de Melob8f8eb82016-03-22 13:09:37 -0300459 struct perf_evsel *evsel,
Andi Kleen140aead2016-01-30 09:06:49 -0800460 double avg,
Jin Yaoe0128b32017-12-05 22:03:05 +0800461 struct perf_stat_output_ctx *out,
462 struct runtime_stat *st)
Jiri Olsaf87027b2015-06-03 16:25:59 +0200463{
464 double total, ratio = 0.0;
465 const char *color;
466 int ctx = evsel_context(evsel);
467
Jin Yaoe0128b32017-12-05 22:03:05 +0800468 total = runtime_stat_avg(st, STAT_BRANCHES, ctx, cpu);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200469
470 if (total)
471 ratio = avg / total * 100.0;
472
473 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
474
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200475 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all branches", ratio);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200476}
477
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200478static void print_l1_dcache_misses(struct perf_stat_config *config,
479 int cpu,
Arnaldo Carvalho de Melob8f8eb82016-03-22 13:09:37 -0300480 struct perf_evsel *evsel,
Andi Kleen140aead2016-01-30 09:06:49 -0800481 double avg,
Jin Yaoe0128b32017-12-05 22:03:05 +0800482 struct perf_stat_output_ctx *out,
483 struct runtime_stat *st)
484
Jiri Olsaf87027b2015-06-03 16:25:59 +0200485{
486 double total, ratio = 0.0;
487 const char *color;
488 int ctx = evsel_context(evsel);
489
Jin Yaoe0128b32017-12-05 22:03:05 +0800490 total = runtime_stat_avg(st, STAT_L1_DCACHE, ctx, cpu);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200491
492 if (total)
493 ratio = avg / total * 100.0;
494
495 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
496
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200497 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all L1-dcache hits", ratio);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200498}
499
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200500static void print_l1_icache_misses(struct perf_stat_config *config,
501 int cpu,
Arnaldo Carvalho de Melob8f8eb82016-03-22 13:09:37 -0300502 struct perf_evsel *evsel,
Andi Kleen140aead2016-01-30 09:06:49 -0800503 double avg,
Jin Yaoe0128b32017-12-05 22:03:05 +0800504 struct perf_stat_output_ctx *out,
505 struct runtime_stat *st)
506
Jiri Olsaf87027b2015-06-03 16:25:59 +0200507{
508 double total, ratio = 0.0;
509 const char *color;
510 int ctx = evsel_context(evsel);
511
Jin Yaoe0128b32017-12-05 22:03:05 +0800512 total = runtime_stat_avg(st, STAT_L1_ICACHE, ctx, cpu);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200513
514 if (total)
515 ratio = avg / total * 100.0;
516
517 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200518 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all L1-icache hits", ratio);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200519}
520
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200521static void print_dtlb_cache_misses(struct perf_stat_config *config,
522 int cpu,
Arnaldo Carvalho de Melob8f8eb82016-03-22 13:09:37 -0300523 struct perf_evsel *evsel,
Andi Kleen140aead2016-01-30 09:06:49 -0800524 double avg,
Jin Yaoe0128b32017-12-05 22:03:05 +0800525 struct perf_stat_output_ctx *out,
526 struct runtime_stat *st)
Jiri Olsaf87027b2015-06-03 16:25:59 +0200527{
528 double total, ratio = 0.0;
529 const char *color;
530 int ctx = evsel_context(evsel);
531
Jin Yaoe0128b32017-12-05 22:03:05 +0800532 total = runtime_stat_avg(st, STAT_DTLB_CACHE, ctx, cpu);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200533
534 if (total)
535 ratio = avg / total * 100.0;
536
537 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200538 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all dTLB cache hits", ratio);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200539}
540
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200541static void print_itlb_cache_misses(struct perf_stat_config *config,
542 int cpu,
Arnaldo Carvalho de Melob8f8eb82016-03-22 13:09:37 -0300543 struct perf_evsel *evsel,
Andi Kleen140aead2016-01-30 09:06:49 -0800544 double avg,
Jin Yaoe0128b32017-12-05 22:03:05 +0800545 struct perf_stat_output_ctx *out,
546 struct runtime_stat *st)
Jiri Olsaf87027b2015-06-03 16:25:59 +0200547{
548 double total, ratio = 0.0;
549 const char *color;
550 int ctx = evsel_context(evsel);
551
Jin Yaoe0128b32017-12-05 22:03:05 +0800552 total = runtime_stat_avg(st, STAT_ITLB_CACHE, ctx, cpu);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200553
554 if (total)
555 ratio = avg / total * 100.0;
556
557 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200558 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all iTLB cache hits", ratio);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200559}
560
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200561static void print_ll_cache_misses(struct perf_stat_config *config,
562 int cpu,
Arnaldo Carvalho de Melob8f8eb82016-03-22 13:09:37 -0300563 struct perf_evsel *evsel,
Andi Kleen140aead2016-01-30 09:06:49 -0800564 double avg,
Jin Yaoe0128b32017-12-05 22:03:05 +0800565 struct perf_stat_output_ctx *out,
566 struct runtime_stat *st)
Jiri Olsaf87027b2015-06-03 16:25:59 +0200567{
568 double total, ratio = 0.0;
569 const char *color;
570 int ctx = evsel_context(evsel);
571
Jin Yaoe0128b32017-12-05 22:03:05 +0800572 total = runtime_stat_avg(st, STAT_LL_CACHE, ctx, cpu);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200573
574 if (total)
575 ratio = avg / total * 100.0;
576
577 color = get_ratio_color(GRC_CACHE_MISSES, ratio);
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200578 out->print_metric(config, out->ctx, color, "%7.2f%%", "of all LL-cache hits", ratio);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200579}
580
Andi Kleen239bd472016-05-24 12:52:37 -0700581/*
582 * High level "TopDown" CPU core pipe line bottleneck break down.
583 *
584 * Basic concept following
585 * Yasin, A Top Down Method for Performance analysis and Counter architecture
586 * ISPASS14
587 *
588 * The CPU pipeline is divided into 4 areas that can be bottlenecks:
589 *
590 * Frontend -> Backend -> Retiring
591 * BadSpeculation in addition means out of order execution that is thrown away
592 * (for example branch mispredictions)
593 * Frontend is instruction decoding.
594 * Backend is execution, like computation and accessing data in memory
595 * Retiring is good execution that is not directly bottlenecked
596 *
597 * The formulas are computed in slots.
598 * A slot is an entry in the pipeline each for the pipeline width
599 * (for example a 4-wide pipeline has 4 slots for each cycle)
600 *
601 * Formulas:
602 * BadSpeculation = ((SlotsIssued - SlotsRetired) + RecoveryBubbles) /
603 * TotalSlots
604 * Retiring = SlotsRetired / TotalSlots
605 * FrontendBound = FetchBubbles / TotalSlots
606 * BackendBound = 1.0 - BadSpeculation - Retiring - FrontendBound
607 *
608 * The kernel provides the mapping to the low level CPU events and any scaling
609 * needed for the CPU pipeline width, for example:
610 *
611 * TotalSlots = Cycles * 4
612 *
613 * The scaling factor is communicated in the sysfs unit.
614 *
615 * In some cases the CPU may not be able to measure all the formulas due to
616 * missing events. In this case multiple formulas are combined, as possible.
617 *
618 * Full TopDown supports more levels to sub-divide each area: for example
619 * BackendBound into computing bound and memory bound. For now we only
620 * support Level 1 TopDown.
621 */
622
623static double sanitize_val(double x)
624{
625 if (x < 0 && x >= -0.02)
626 return 0.0;
627 return x;
628}
629
Jin Yaoe0128b32017-12-05 22:03:05 +0800630static double td_total_slots(int ctx, int cpu, struct runtime_stat *st)
Andi Kleen239bd472016-05-24 12:52:37 -0700631{
Jin Yaoe0128b32017-12-05 22:03:05 +0800632 return runtime_stat_avg(st, STAT_TOPDOWN_TOTAL_SLOTS, ctx, cpu);
Andi Kleen239bd472016-05-24 12:52:37 -0700633}
634
Jin Yaoe0128b32017-12-05 22:03:05 +0800635static double td_bad_spec(int ctx, int cpu, struct runtime_stat *st)
Andi Kleen239bd472016-05-24 12:52:37 -0700636{
637 double bad_spec = 0;
638 double total_slots;
639 double total;
640
Jin Yaoe0128b32017-12-05 22:03:05 +0800641 total = runtime_stat_avg(st, STAT_TOPDOWN_SLOTS_ISSUED, ctx, cpu) -
642 runtime_stat_avg(st, STAT_TOPDOWN_SLOTS_RETIRED, ctx, cpu) +
643 runtime_stat_avg(st, STAT_TOPDOWN_RECOVERY_BUBBLES, ctx, cpu);
644
645 total_slots = td_total_slots(ctx, cpu, st);
Andi Kleen239bd472016-05-24 12:52:37 -0700646 if (total_slots)
647 bad_spec = total / total_slots;
648 return sanitize_val(bad_spec);
649}
650
Jin Yaoe0128b32017-12-05 22:03:05 +0800651static double td_retiring(int ctx, int cpu, struct runtime_stat *st)
Andi Kleen239bd472016-05-24 12:52:37 -0700652{
653 double retiring = 0;
Jin Yaoe0128b32017-12-05 22:03:05 +0800654 double total_slots = td_total_slots(ctx, cpu, st);
655 double ret_slots = runtime_stat_avg(st, STAT_TOPDOWN_SLOTS_RETIRED,
656 ctx, cpu);
Andi Kleen239bd472016-05-24 12:52:37 -0700657
658 if (total_slots)
659 retiring = ret_slots / total_slots;
660 return retiring;
661}
662
Jin Yaoe0128b32017-12-05 22:03:05 +0800663static double td_fe_bound(int ctx, int cpu, struct runtime_stat *st)
Andi Kleen239bd472016-05-24 12:52:37 -0700664{
665 double fe_bound = 0;
Jin Yaoe0128b32017-12-05 22:03:05 +0800666 double total_slots = td_total_slots(ctx, cpu, st);
667 double fetch_bub = runtime_stat_avg(st, STAT_TOPDOWN_FETCH_BUBBLES,
668 ctx, cpu);
Andi Kleen239bd472016-05-24 12:52:37 -0700669
670 if (total_slots)
671 fe_bound = fetch_bub / total_slots;
672 return fe_bound;
673}
674
Jin Yaoe0128b32017-12-05 22:03:05 +0800675static double td_be_bound(int ctx, int cpu, struct runtime_stat *st)
Andi Kleen239bd472016-05-24 12:52:37 -0700676{
Jin Yaoe0128b32017-12-05 22:03:05 +0800677 double sum = (td_fe_bound(ctx, cpu, st) +
678 td_bad_spec(ctx, cpu, st) +
679 td_retiring(ctx, cpu, st));
Andi Kleen239bd472016-05-24 12:52:37 -0700680 if (sum == 0)
681 return 0;
682 return sanitize_val(1.0 - sum);
683}
684
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200685static void print_smi_cost(struct perf_stat_config *config,
686 int cpu, struct perf_evsel *evsel,
Jin Yaoe0128b32017-12-05 22:03:05 +0800687 struct perf_stat_output_ctx *out,
688 struct runtime_stat *st)
Kan Liangdaefd0b2017-05-26 12:05:38 -0700689{
690 double smi_num, aperf, cycles, cost = 0.0;
691 int ctx = evsel_context(evsel);
692 const char *color = NULL;
693
Jin Yaoe0128b32017-12-05 22:03:05 +0800694 smi_num = runtime_stat_avg(st, STAT_SMI_NUM, ctx, cpu);
695 aperf = runtime_stat_avg(st, STAT_APERF, ctx, cpu);
696 cycles = runtime_stat_avg(st, STAT_CYCLES, ctx, cpu);
Kan Liangdaefd0b2017-05-26 12:05:38 -0700697
698 if ((cycles == 0) || (aperf == 0))
699 return;
700
701 if (smi_num)
702 cost = (aperf - cycles) / aperf * 100.00;
703
704 if (cost > 10)
705 color = PERF_COLOR_RED;
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200706 out->print_metric(config, out->ctx, color, "%8.1f%%", "SMI cycles%", cost);
707 out->print_metric(config, out->ctx, NULL, "%4.0f", "SMI#", smi_num);
Kan Liangdaefd0b2017-05-26 12:05:38 -0700708}
709
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200710static void generic_metric(struct perf_stat_config *config,
711 const char *metric_expr,
Andi Kleenbba49af2017-08-31 12:40:28 -0700712 struct perf_evsel **metric_events,
713 char *name,
714 const char *metric_name,
715 double avg,
716 int cpu,
Jin Yaoe0128b32017-12-05 22:03:05 +0800717 struct perf_stat_output_ctx *out,
718 struct runtime_stat *st)
Andi Kleenbba49af2017-08-31 12:40:28 -0700719{
720 print_metric_t print_metric = out->print_metric;
721 struct parse_ctx pctx;
722 double ratio;
723 int i;
724 void *ctxp = out->ctx;
725
726 expr__ctx_init(&pctx);
727 expr__add_id(&pctx, name, avg);
728 for (i = 0; metric_events[i]; i++) {
729 struct saved_value *v;
Andi Kleenfd48aad2017-08-31 12:40:34 -0700730 struct stats *stats;
731 double scale;
Andi Kleenbba49af2017-08-31 12:40:28 -0700732
Andi Kleenfd48aad2017-08-31 12:40:34 -0700733 if (!strcmp(metric_events[i]->name, "duration_time")) {
734 stats = &walltime_nsecs_stats;
735 scale = 1e-9;
736 } else {
Jin Yao1fcd0392017-12-05 22:03:04 +0800737 v = saved_value_lookup(metric_events[i], cpu, false,
Jin Yaoe0128b32017-12-05 22:03:05 +0800738 STAT_NONE, 0, st);
Andi Kleenfd48aad2017-08-31 12:40:34 -0700739 if (!v)
740 break;
741 stats = &v->stats;
742 scale = 1.0;
743 }
744 expr__add_id(&pctx, metric_events[i]->name, avg_stats(stats)*scale);
Andi Kleenbba49af2017-08-31 12:40:28 -0700745 }
746 if (!metric_events[i]) {
747 const char *p = metric_expr;
748
749 if (expr__parse(&ratio, &pctx, &p) == 0)
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200750 print_metric(config, ctxp, NULL, "%8.1f",
Andi Kleenbba49af2017-08-31 12:40:28 -0700751 metric_name ?
752 metric_name :
753 out->force_header ? name : "",
754 ratio);
755 else
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200756 print_metric(config, ctxp, NULL, NULL,
Andi Kleen4ed962e2017-08-31 12:40:29 -0700757 out->force_header ?
758 (metric_name ? metric_name : name) : "", 0);
Andi Kleenbba49af2017-08-31 12:40:28 -0700759 } else
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200760 print_metric(config, ctxp, NULL, NULL, "", 0);
Andi Kleenbba49af2017-08-31 12:40:28 -0700761}
762
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200763void perf_stat__print_shadow_stats(struct perf_stat_config *config,
764 struct perf_evsel *evsel,
Andi Kleen140aead2016-01-30 09:06:49 -0800765 double avg, int cpu,
Andi Kleenb18f3e32017-08-31 12:40:31 -0700766 struct perf_stat_output_ctx *out,
Jin Yaoe0128b32017-12-05 22:03:05 +0800767 struct rblist *metric_events,
768 struct runtime_stat *st)
Jiri Olsaf87027b2015-06-03 16:25:59 +0200769{
Andi Kleen140aead2016-01-30 09:06:49 -0800770 void *ctxp = out->ctx;
771 print_metric_t print_metric = out->print_metric;
Jiri Olsaf87027b2015-06-03 16:25:59 +0200772 double total, ratio = 0.0, total2;
Andi Kleen239bd472016-05-24 12:52:37 -0700773 const char *color = NULL;
Jiri Olsaf87027b2015-06-03 16:25:59 +0200774 int ctx = evsel_context(evsel);
Andi Kleenb18f3e32017-08-31 12:40:31 -0700775 struct metric_event *me;
776 int num = 1;
Jiri Olsaf87027b2015-06-03 16:25:59 +0200777
778 if (perf_evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS)) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800779 total = runtime_stat_avg(st, STAT_CYCLES, ctx, cpu);
780
Jiri Olsaf87027b2015-06-03 16:25:59 +0200781 if (total) {
782 ratio = avg / total;
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200783 print_metric(config, ctxp, NULL, "%7.2f ",
Andi Kleen140aead2016-01-30 09:06:49 -0800784 "insn per cycle", ratio);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200785 } else {
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200786 print_metric(config, ctxp, NULL, NULL, "insn per cycle", 0);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200787 }
Jin Yaoe0128b32017-12-05 22:03:05 +0800788
789 total = runtime_stat_avg(st, STAT_STALLED_CYCLES_FRONT,
790 ctx, cpu);
791
792 total = max(total, runtime_stat_avg(st,
793 STAT_STALLED_CYCLES_BACK,
794 ctx, cpu));
Jiri Olsaf87027b2015-06-03 16:25:59 +0200795
796 if (total && avg) {
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200797 out->new_line(config, ctxp);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200798 ratio = total / avg;
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200799 print_metric(config, ctxp, NULL, "%7.2f ",
Andi Kleen140aead2016-01-30 09:06:49 -0800800 "stalled cycles per insn",
801 ratio);
Andi Kleenfb4605b2016-03-01 10:57:52 -0800802 } else if (have_frontend_stalled) {
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200803 print_metric(config, ctxp, NULL, NULL,
Andi Kleen140aead2016-01-30 09:06:49 -0800804 "stalled cycles per insn", 0);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200805 }
Andi Kleen140aead2016-01-30 09:06:49 -0800806 } else if (perf_evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES)) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800807 if (runtime_stat_n(st, STAT_BRANCHES, ctx, cpu) != 0)
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200808 print_branch_misses(config, cpu, evsel, avg, out, st);
Andi Kleen140aead2016-01-30 09:06:49 -0800809 else
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200810 print_metric(config, ctxp, NULL, NULL, "of all branches", 0);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200811 } else if (
812 evsel->attr.type == PERF_TYPE_HW_CACHE &&
813 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1D |
814 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
Andi Kleen140aead2016-01-30 09:06:49 -0800815 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800816
817 if (runtime_stat_n(st, STAT_L1_DCACHE, ctx, cpu) != 0)
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200818 print_l1_dcache_misses(config, cpu, evsel, avg, out, st);
Andi Kleen140aead2016-01-30 09:06:49 -0800819 else
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200820 print_metric(config, ctxp, NULL, NULL, "of all L1-dcache hits", 0);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200821 } else if (
822 evsel->attr.type == PERF_TYPE_HW_CACHE &&
823 evsel->attr.config == ( PERF_COUNT_HW_CACHE_L1I |
824 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
Andi Kleen140aead2016-01-30 09:06:49 -0800825 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800826
827 if (runtime_stat_n(st, STAT_L1_ICACHE, ctx, cpu) != 0)
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200828 print_l1_icache_misses(config, cpu, evsel, avg, out, st);
Andi Kleen140aead2016-01-30 09:06:49 -0800829 else
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200830 print_metric(config, ctxp, NULL, NULL, "of all L1-icache hits", 0);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200831 } else if (
832 evsel->attr.type == PERF_TYPE_HW_CACHE &&
833 evsel->attr.config == ( PERF_COUNT_HW_CACHE_DTLB |
834 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
Andi Kleen140aead2016-01-30 09:06:49 -0800835 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800836
837 if (runtime_stat_n(st, STAT_DTLB_CACHE, ctx, cpu) != 0)
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200838 print_dtlb_cache_misses(config, cpu, evsel, avg, out, st);
Andi Kleen140aead2016-01-30 09:06:49 -0800839 else
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200840 print_metric(config, ctxp, NULL, NULL, "of all dTLB cache hits", 0);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200841 } else if (
842 evsel->attr.type == PERF_TYPE_HW_CACHE &&
843 evsel->attr.config == ( PERF_COUNT_HW_CACHE_ITLB |
844 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
Andi Kleen140aead2016-01-30 09:06:49 -0800845 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800846
847 if (runtime_stat_n(st, STAT_ITLB_CACHE, ctx, cpu) != 0)
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200848 print_itlb_cache_misses(config, cpu, evsel, avg, out, st);
Andi Kleen140aead2016-01-30 09:06:49 -0800849 else
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200850 print_metric(config, ctxp, NULL, NULL, "of all iTLB cache hits", 0);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200851 } else if (
852 evsel->attr.type == PERF_TYPE_HW_CACHE &&
853 evsel->attr.config == ( PERF_COUNT_HW_CACHE_LL |
854 ((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
Andi Kleen140aead2016-01-30 09:06:49 -0800855 ((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16))) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800856
857 if (runtime_stat_n(st, STAT_LL_CACHE, ctx, cpu) != 0)
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200858 print_ll_cache_misses(config, cpu, evsel, avg, out, st);
Andi Kleen140aead2016-01-30 09:06:49 -0800859 else
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200860 print_metric(config, ctxp, NULL, NULL, "of all LL-cache hits", 0);
Andi Kleen140aead2016-01-30 09:06:49 -0800861 } else if (perf_evsel__match(evsel, HARDWARE, HW_CACHE_MISSES)) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800862 total = runtime_stat_avg(st, STAT_CACHEREFS, ctx, cpu);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200863
864 if (total)
865 ratio = avg * 100 / total;
866
Jin Yaoe0128b32017-12-05 22:03:05 +0800867 if (runtime_stat_n(st, STAT_CACHEREFS, ctx, cpu) != 0)
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200868 print_metric(config, ctxp, NULL, "%8.3f %%",
Andi Kleen140aead2016-01-30 09:06:49 -0800869 "of all cache refs", ratio);
870 else
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200871 print_metric(config, ctxp, NULL, NULL, "of all cache refs", 0);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200872 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND)) {
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200873 print_stalled_cycles_frontend(config, cpu, evsel, avg, out, st);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200874 } else if (perf_evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_BACKEND)) {
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200875 print_stalled_cycles_backend(config, cpu, evsel, avg, out, st);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200876 } else if (perf_evsel__match(evsel, HARDWARE, HW_CPU_CYCLES)) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800877 total = runtime_stat_avg(st, STAT_NSECS, 0, cpu);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200878
879 if (total) {
880 ratio = avg / total;
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200881 print_metric(config, ctxp, NULL, "%8.3f", "GHz", ratio);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200882 } else {
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200883 print_metric(config, ctxp, NULL, NULL, "Ghz", 0);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200884 }
885 } else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX)) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800886 total = runtime_stat_avg(st, STAT_CYCLES, ctx, cpu);
887
Jiri Olsaf87027b2015-06-03 16:25:59 +0200888 if (total)
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200889 print_metric(config, ctxp, NULL,
Andi Kleen140aead2016-01-30 09:06:49 -0800890 "%7.2f%%", "transactional cycles",
891 100.0 * (avg / total));
892 else
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200893 print_metric(config, ctxp, NULL, NULL, "transactional cycles",
Andi Kleen140aead2016-01-30 09:06:49 -0800894 0);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200895 } else if (perf_stat_evsel__is(evsel, CYCLES_IN_TX_CP)) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800896 total = runtime_stat_avg(st, STAT_CYCLES, ctx, cpu);
897 total2 = runtime_stat_avg(st, STAT_CYCLES_IN_TX, ctx, cpu);
898
Jiri Olsaf87027b2015-06-03 16:25:59 +0200899 if (total2 < avg)
900 total2 = avg;
901 if (total)
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200902 print_metric(config, ctxp, NULL, "%7.2f%%", "aborted cycles",
Jiri Olsaf87027b2015-06-03 16:25:59 +0200903 100.0 * ((total2-avg) / total));
Andi Kleen140aead2016-01-30 09:06:49 -0800904 else
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200905 print_metric(config, ctxp, NULL, NULL, "aborted cycles", 0);
Andi Kleen140aead2016-01-30 09:06:49 -0800906 } else if (perf_stat_evsel__is(evsel, TRANSACTION_START)) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800907 total = runtime_stat_avg(st, STAT_CYCLES_IN_TX,
908 ctx, cpu);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200909
Andi Kleen54976282015-07-27 16:24:51 -0700910 if (avg)
Jiri Olsaf87027b2015-06-03 16:25:59 +0200911 ratio = total / avg;
912
Jin Yaoe0128b32017-12-05 22:03:05 +0800913 if (runtime_stat_n(st, STAT_CYCLES_IN_TX, ctx, cpu) != 0)
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200914 print_metric(config, ctxp, NULL, "%8.0f",
Andi Kleen140aead2016-01-30 09:06:49 -0800915 "cycles / transaction", ratio);
916 else
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200917 print_metric(config, ctxp, NULL, NULL, "cycles / transaction",
Jin Yaoe0128b32017-12-05 22:03:05 +0800918 0);
Andi Kleen140aead2016-01-30 09:06:49 -0800919 } else if (perf_stat_evsel__is(evsel, ELISION_START)) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800920 total = runtime_stat_avg(st, STAT_CYCLES_IN_TX,
921 ctx, cpu);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200922
Andi Kleen54976282015-07-27 16:24:51 -0700923 if (avg)
Jiri Olsaf87027b2015-06-03 16:25:59 +0200924 ratio = total / avg;
925
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200926 print_metric(config, ctxp, NULL, "%8.0f", "cycles / elision", ratio);
Jiri Olsa0aa802a2018-07-20 13:00:34 +0200927 } else if (perf_evsel__is_clock(evsel)) {
Andi Kleen4579ecc2015-11-02 17:50:20 -0800928 if ((ratio = avg_stats(&walltime_nsecs_stats)) != 0)
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200929 print_metric(config, ctxp, NULL, "%8.3f", "CPUs utilized",
Jiri Olsa0aa802a2018-07-20 13:00:34 +0200930 avg / (ratio * evsel->scale));
Andi Kleen4579ecc2015-11-02 17:50:20 -0800931 else
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200932 print_metric(config, ctxp, NULL, NULL, "CPUs utilized", 0);
Andi Kleen239bd472016-05-24 12:52:37 -0700933 } else if (perf_stat_evsel__is(evsel, TOPDOWN_FETCH_BUBBLES)) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800934 double fe_bound = td_fe_bound(ctx, cpu, st);
Andi Kleen239bd472016-05-24 12:52:37 -0700935
936 if (fe_bound > 0.2)
937 color = PERF_COLOR_RED;
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200938 print_metric(config, ctxp, color, "%8.1f%%", "frontend bound",
Andi Kleen239bd472016-05-24 12:52:37 -0700939 fe_bound * 100.);
940 } else if (perf_stat_evsel__is(evsel, TOPDOWN_SLOTS_RETIRED)) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800941 double retiring = td_retiring(ctx, cpu, st);
Andi Kleen239bd472016-05-24 12:52:37 -0700942
943 if (retiring > 0.7)
944 color = PERF_COLOR_GREEN;
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200945 print_metric(config, ctxp, color, "%8.1f%%", "retiring",
Andi Kleen239bd472016-05-24 12:52:37 -0700946 retiring * 100.);
947 } else if (perf_stat_evsel__is(evsel, TOPDOWN_RECOVERY_BUBBLES)) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800948 double bad_spec = td_bad_spec(ctx, cpu, st);
Andi Kleen239bd472016-05-24 12:52:37 -0700949
950 if (bad_spec > 0.1)
951 color = PERF_COLOR_RED;
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200952 print_metric(config, ctxp, color, "%8.1f%%", "bad speculation",
Andi Kleen239bd472016-05-24 12:52:37 -0700953 bad_spec * 100.);
954 } else if (perf_stat_evsel__is(evsel, TOPDOWN_SLOTS_ISSUED)) {
Jin Yaoe0128b32017-12-05 22:03:05 +0800955 double be_bound = td_be_bound(ctx, cpu, st);
Andi Kleen239bd472016-05-24 12:52:37 -0700956 const char *name = "backend bound";
957 static int have_recovery_bubbles = -1;
958
959 /* In case the CPU does not support topdown-recovery-bubbles */
960 if (have_recovery_bubbles < 0)
961 have_recovery_bubbles = pmu_have_event("cpu",
962 "topdown-recovery-bubbles");
963 if (!have_recovery_bubbles)
964 name = "backend bound/bad spec";
965
966 if (be_bound > 0.2)
967 color = PERF_COLOR_RED;
Jin Yaoe0128b32017-12-05 22:03:05 +0800968 if (td_total_slots(ctx, cpu, st) > 0)
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200969 print_metric(config, ctxp, color, "%8.1f%%", name,
Andi Kleen239bd472016-05-24 12:52:37 -0700970 be_bound * 100.);
971 else
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200972 print_metric(config, ctxp, NULL, NULL, name, 0);
Andi Kleen37932c12017-03-20 13:17:08 -0700973 } else if (evsel->metric_expr) {
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200974 generic_metric(config, evsel->metric_expr, evsel->metric_events, evsel->name,
Jin Yaoe0128b32017-12-05 22:03:05 +0800975 evsel->metric_name, avg, cpu, out, st);
976 } else if (runtime_stat_n(st, STAT_NSECS, 0, cpu) != 0) {
Jiri Olsaf87027b2015-06-03 16:25:59 +0200977 char unit = 'M';
Andi Kleen140aead2016-01-30 09:06:49 -0800978 char unit_buf[10];
Jiri Olsaf87027b2015-06-03 16:25:59 +0200979
Jin Yaoe0128b32017-12-05 22:03:05 +0800980 total = runtime_stat_avg(st, STAT_NSECS, 0, cpu);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200981
982 if (total)
983 ratio = 1000.0 * avg / total;
984 if (ratio < 0.001) {
985 ratio *= 1000;
986 unit = 'K';
987 }
Andi Kleen140aead2016-01-30 09:06:49 -0800988 snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit);
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200989 print_metric(config, ctxp, NULL, "%8.3f", unit_buf, ratio);
Kan Liangdaefd0b2017-05-26 12:05:38 -0700990 } else if (perf_stat_evsel__is(evsel, SMI_NUM)) {
Jiri Olsa6ca9a082018-08-30 08:32:28 +0200991 print_smi_cost(config, cpu, evsel, out, st);
Jiri Olsaf87027b2015-06-03 16:25:59 +0200992 } else {
Andi Kleenb18f3e32017-08-31 12:40:31 -0700993 num = 0;
Jiri Olsaf87027b2015-06-03 16:25:59 +0200994 }
Andi Kleenb18f3e32017-08-31 12:40:31 -0700995
996 if ((me = metricgroup__lookup(metric_events, evsel, false)) != NULL) {
997 struct metric_expr *mexp;
998
999 list_for_each_entry (mexp, &me->head, nd) {
1000 if (num++ > 0)
Jiri Olsa6ca9a082018-08-30 08:32:28 +02001001 out->new_line(config, ctxp);
1002 generic_metric(config, mexp->metric_expr, mexp->metric_events,
Andi Kleenb18f3e32017-08-31 12:40:31 -07001003 evsel->name, mexp->metric_name,
Jin Yaoe0128b32017-12-05 22:03:05 +08001004 avg, cpu, out, st);
Andi Kleenb18f3e32017-08-31 12:40:31 -07001005 }
1006 }
1007 if (num == 0)
Jiri Olsa6ca9a082018-08-30 08:32:28 +02001008 print_metric(config, ctxp, NULL, NULL, NULL, 0);
Jiri Olsaf87027b2015-06-03 16:25:59 +02001009}