Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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) }