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