162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <math.h>
362306a36Sopenharmony_ci#include <stdio.h>
462306a36Sopenharmony_ci#include "evsel.h"
562306a36Sopenharmony_ci#include "stat.h"
662306a36Sopenharmony_ci#include "color.h"
762306a36Sopenharmony_ci#include "debug.h"
862306a36Sopenharmony_ci#include "pmu.h"
962306a36Sopenharmony_ci#include "rblist.h"
1062306a36Sopenharmony_ci#include "evlist.h"
1162306a36Sopenharmony_ci#include "expr.h"
1262306a36Sopenharmony_ci#include "metricgroup.h"
1362306a36Sopenharmony_ci#include "cgroup.h"
1462306a36Sopenharmony_ci#include "units.h"
1562306a36Sopenharmony_ci#include <linux/zalloc.h>
1662306a36Sopenharmony_ci#include "iostat.h"
1762306a36Sopenharmony_ci#include "util/hashmap.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistruct stats walltime_nsecs_stats;
2062306a36Sopenharmony_cistruct rusage_stats ru_stats;
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_cienum {
2362306a36Sopenharmony_ci	CTX_BIT_USER	= 1 << 0,
2462306a36Sopenharmony_ci	CTX_BIT_KERNEL	= 1 << 1,
2562306a36Sopenharmony_ci	CTX_BIT_HV	= 1 << 2,
2662306a36Sopenharmony_ci	CTX_BIT_HOST	= 1 << 3,
2762306a36Sopenharmony_ci	CTX_BIT_IDLE	= 1 << 4,
2862306a36Sopenharmony_ci	CTX_BIT_MAX	= 1 << 5,
2962306a36Sopenharmony_ci};
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_cienum stat_type {
3262306a36Sopenharmony_ci	STAT_NONE = 0,
3362306a36Sopenharmony_ci	STAT_NSECS,
3462306a36Sopenharmony_ci	STAT_CYCLES,
3562306a36Sopenharmony_ci	STAT_INSTRUCTIONS,
3662306a36Sopenharmony_ci	STAT_STALLED_CYCLES_FRONT,
3762306a36Sopenharmony_ci	STAT_STALLED_CYCLES_BACK,
3862306a36Sopenharmony_ci	STAT_BRANCHES,
3962306a36Sopenharmony_ci	STAT_BRANCH_MISS,
4062306a36Sopenharmony_ci	STAT_CACHE_REFS,
4162306a36Sopenharmony_ci	STAT_CACHE_MISSES,
4262306a36Sopenharmony_ci	STAT_L1_DCACHE,
4362306a36Sopenharmony_ci	STAT_L1_ICACHE,
4462306a36Sopenharmony_ci	STAT_LL_CACHE,
4562306a36Sopenharmony_ci	STAT_ITLB_CACHE,
4662306a36Sopenharmony_ci	STAT_DTLB_CACHE,
4762306a36Sopenharmony_ci	STAT_L1D_MISS,
4862306a36Sopenharmony_ci	STAT_L1I_MISS,
4962306a36Sopenharmony_ci	STAT_LL_MISS,
5062306a36Sopenharmony_ci	STAT_DTLB_MISS,
5162306a36Sopenharmony_ci	STAT_ITLB_MISS,
5262306a36Sopenharmony_ci	STAT_MAX
5362306a36Sopenharmony_ci};
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_cistatic int evsel_context(const struct evsel *evsel)
5662306a36Sopenharmony_ci{
5762306a36Sopenharmony_ci	int ctx = 0;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (evsel->core.attr.exclude_kernel)
6062306a36Sopenharmony_ci		ctx |= CTX_BIT_KERNEL;
6162306a36Sopenharmony_ci	if (evsel->core.attr.exclude_user)
6262306a36Sopenharmony_ci		ctx |= CTX_BIT_USER;
6362306a36Sopenharmony_ci	if (evsel->core.attr.exclude_hv)
6462306a36Sopenharmony_ci		ctx |= CTX_BIT_HV;
6562306a36Sopenharmony_ci	if (evsel->core.attr.exclude_host)
6662306a36Sopenharmony_ci		ctx |= CTX_BIT_HOST;
6762306a36Sopenharmony_ci	if (evsel->core.attr.exclude_idle)
6862306a36Sopenharmony_ci		ctx |= CTX_BIT_IDLE;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	return ctx;
7162306a36Sopenharmony_ci}
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_civoid perf_stat__reset_shadow_stats(void)
7462306a36Sopenharmony_ci{
7562306a36Sopenharmony_ci	memset(&walltime_nsecs_stats, 0, sizeof(walltime_nsecs_stats));
7662306a36Sopenharmony_ci	memset(&ru_stats, 0, sizeof(ru_stats));
7762306a36Sopenharmony_ci}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cistatic enum stat_type evsel__stat_type(const struct evsel *evsel)
8062306a36Sopenharmony_ci{
8162306a36Sopenharmony_ci	/* Fake perf_hw_cache_op_id values for use with evsel__match. */
8262306a36Sopenharmony_ci	u64 PERF_COUNT_hw_cache_l1d_miss = PERF_COUNT_HW_CACHE_L1D |
8362306a36Sopenharmony_ci		((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
8462306a36Sopenharmony_ci		((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16);
8562306a36Sopenharmony_ci	u64 PERF_COUNT_hw_cache_l1i_miss = PERF_COUNT_HW_CACHE_L1I |
8662306a36Sopenharmony_ci		((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
8762306a36Sopenharmony_ci		((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16);
8862306a36Sopenharmony_ci	u64 PERF_COUNT_hw_cache_ll_miss = PERF_COUNT_HW_CACHE_LL |
8962306a36Sopenharmony_ci		((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
9062306a36Sopenharmony_ci		((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16);
9162306a36Sopenharmony_ci	u64 PERF_COUNT_hw_cache_dtlb_miss = PERF_COUNT_HW_CACHE_DTLB |
9262306a36Sopenharmony_ci		((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
9362306a36Sopenharmony_ci		((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16);
9462306a36Sopenharmony_ci	u64 PERF_COUNT_hw_cache_itlb_miss = PERF_COUNT_HW_CACHE_ITLB |
9562306a36Sopenharmony_ci		((PERF_COUNT_HW_CACHE_OP_READ) << 8) |
9662306a36Sopenharmony_ci		((PERF_COUNT_HW_CACHE_RESULT_MISS) << 16);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	if (evsel__is_clock(evsel))
9962306a36Sopenharmony_ci		return STAT_NSECS;
10062306a36Sopenharmony_ci	else if (evsel__match(evsel, HARDWARE, HW_CPU_CYCLES))
10162306a36Sopenharmony_ci		return STAT_CYCLES;
10262306a36Sopenharmony_ci	else if (evsel__match(evsel, HARDWARE, HW_INSTRUCTIONS))
10362306a36Sopenharmony_ci		return STAT_INSTRUCTIONS;
10462306a36Sopenharmony_ci	else if (evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_FRONTEND))
10562306a36Sopenharmony_ci		return STAT_STALLED_CYCLES_FRONT;
10662306a36Sopenharmony_ci	else if (evsel__match(evsel, HARDWARE, HW_STALLED_CYCLES_BACKEND))
10762306a36Sopenharmony_ci		return STAT_STALLED_CYCLES_BACK;
10862306a36Sopenharmony_ci	else if (evsel__match(evsel, HARDWARE, HW_BRANCH_INSTRUCTIONS))
10962306a36Sopenharmony_ci		return STAT_BRANCHES;
11062306a36Sopenharmony_ci	else if (evsel__match(evsel, HARDWARE, HW_BRANCH_MISSES))
11162306a36Sopenharmony_ci		return STAT_BRANCH_MISS;
11262306a36Sopenharmony_ci	else if (evsel__match(evsel, HARDWARE, HW_CACHE_REFERENCES))
11362306a36Sopenharmony_ci		return STAT_CACHE_REFS;
11462306a36Sopenharmony_ci	else if (evsel__match(evsel, HARDWARE, HW_CACHE_MISSES))
11562306a36Sopenharmony_ci		return STAT_CACHE_MISSES;
11662306a36Sopenharmony_ci	else if (evsel__match(evsel, HW_CACHE, HW_CACHE_L1D))
11762306a36Sopenharmony_ci		return STAT_L1_DCACHE;
11862306a36Sopenharmony_ci	else if (evsel__match(evsel, HW_CACHE, HW_CACHE_L1I))
11962306a36Sopenharmony_ci		return STAT_L1_ICACHE;
12062306a36Sopenharmony_ci	else if (evsel__match(evsel, HW_CACHE, HW_CACHE_LL))
12162306a36Sopenharmony_ci		return STAT_LL_CACHE;
12262306a36Sopenharmony_ci	else if (evsel__match(evsel, HW_CACHE, HW_CACHE_DTLB))
12362306a36Sopenharmony_ci		return STAT_DTLB_CACHE;
12462306a36Sopenharmony_ci	else if (evsel__match(evsel, HW_CACHE, HW_CACHE_ITLB))
12562306a36Sopenharmony_ci		return STAT_ITLB_CACHE;
12662306a36Sopenharmony_ci	else if (evsel__match(evsel, HW_CACHE, hw_cache_l1d_miss))
12762306a36Sopenharmony_ci		return STAT_L1D_MISS;
12862306a36Sopenharmony_ci	else if (evsel__match(evsel, HW_CACHE, hw_cache_l1i_miss))
12962306a36Sopenharmony_ci		return STAT_L1I_MISS;
13062306a36Sopenharmony_ci	else if (evsel__match(evsel, HW_CACHE, hw_cache_ll_miss))
13162306a36Sopenharmony_ci		return STAT_LL_MISS;
13262306a36Sopenharmony_ci	else if (evsel__match(evsel, HW_CACHE, hw_cache_dtlb_miss))
13362306a36Sopenharmony_ci		return STAT_DTLB_MISS;
13462306a36Sopenharmony_ci	else if (evsel__match(evsel, HW_CACHE, hw_cache_itlb_miss))
13562306a36Sopenharmony_ci		return STAT_ITLB_MISS;
13662306a36Sopenharmony_ci	return STAT_NONE;
13762306a36Sopenharmony_ci}
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_cistatic const char *get_ratio_color(const double ratios[3], double val)
14062306a36Sopenharmony_ci{
14162306a36Sopenharmony_ci	const char *color = PERF_COLOR_NORMAL;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	if (val > ratios[0])
14462306a36Sopenharmony_ci		color = PERF_COLOR_RED;
14562306a36Sopenharmony_ci	else if (val > ratios[1])
14662306a36Sopenharmony_ci		color = PERF_COLOR_MAGENTA;
14762306a36Sopenharmony_ci	else if (val > ratios[2])
14862306a36Sopenharmony_ci		color = PERF_COLOR_YELLOW;
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci	return color;
15162306a36Sopenharmony_ci}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_cistatic double find_stat(const struct evsel *evsel, int aggr_idx, enum stat_type type)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	const struct evsel *cur;
15662306a36Sopenharmony_ci	int evsel_ctx = evsel_context(evsel);
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	evlist__for_each_entry(evsel->evlist, cur) {
15962306a36Sopenharmony_ci		struct perf_stat_aggr *aggr;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci		/* Ignore the evsel that is being searched from. */
16262306a36Sopenharmony_ci		if (evsel == cur)
16362306a36Sopenharmony_ci			continue;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci		/* Ignore evsels that are part of different groups. */
16662306a36Sopenharmony_ci		if (evsel->core.leader->nr_members > 1 &&
16762306a36Sopenharmony_ci		    evsel->core.leader != cur->core.leader)
16862306a36Sopenharmony_ci			continue;
16962306a36Sopenharmony_ci		/* Ignore evsels with mismatched modifiers. */
17062306a36Sopenharmony_ci		if (evsel_ctx != evsel_context(cur))
17162306a36Sopenharmony_ci			continue;
17262306a36Sopenharmony_ci		/* Ignore if not the cgroup we're looking for. */
17362306a36Sopenharmony_ci		if (evsel->cgrp != cur->cgrp)
17462306a36Sopenharmony_ci			continue;
17562306a36Sopenharmony_ci		/* Ignore if not the stat we're looking for. */
17662306a36Sopenharmony_ci		if (type != evsel__stat_type(cur))
17762306a36Sopenharmony_ci			continue;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci		aggr = &cur->stats->aggr[aggr_idx];
18062306a36Sopenharmony_ci		if (type == STAT_NSECS)
18162306a36Sopenharmony_ci			return aggr->counts.val;
18262306a36Sopenharmony_ci		return aggr->counts.val * cur->scale;
18362306a36Sopenharmony_ci	}
18462306a36Sopenharmony_ci	return 0.0;
18562306a36Sopenharmony_ci}
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cistatic void print_ratio(struct perf_stat_config *config,
18862306a36Sopenharmony_ci			const struct evsel *evsel, int aggr_idx,
18962306a36Sopenharmony_ci			double numerator, struct perf_stat_output_ctx *out,
19062306a36Sopenharmony_ci			enum stat_type denominator_type,
19162306a36Sopenharmony_ci			const double color_ratios[3], const char *unit)
19262306a36Sopenharmony_ci{
19362306a36Sopenharmony_ci	double denominator = find_stat(evsel, aggr_idx, denominator_type);
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_ci	if (numerator && denominator) {
19662306a36Sopenharmony_ci		double ratio = numerator / denominator * 100.0;
19762306a36Sopenharmony_ci		const char *color = get_ratio_color(color_ratios, ratio);
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci		out->print_metric(config, out->ctx, color, "%7.2f%%", unit, ratio);
20062306a36Sopenharmony_ci	} else
20162306a36Sopenharmony_ci		out->print_metric(config, out->ctx, NULL, NULL, unit, 0);
20262306a36Sopenharmony_ci}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_cistatic void print_stalled_cycles_front(struct perf_stat_config *config,
20562306a36Sopenharmony_ci				const struct evsel *evsel,
20662306a36Sopenharmony_ci				int aggr_idx, double stalled,
20762306a36Sopenharmony_ci				struct perf_stat_output_ctx *out)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	static const double color_ratios[3] = {50.0, 30.0, 10.0};
21062306a36Sopenharmony_ci
21162306a36Sopenharmony_ci	print_ratio(config, evsel, aggr_idx, stalled, out, STAT_CYCLES, color_ratios,
21262306a36Sopenharmony_ci		    "frontend cycles idle");
21362306a36Sopenharmony_ci}
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_cistatic void print_stalled_cycles_back(struct perf_stat_config *config,
21662306a36Sopenharmony_ci				const struct evsel *evsel,
21762306a36Sopenharmony_ci				int aggr_idx, double stalled,
21862306a36Sopenharmony_ci				struct perf_stat_output_ctx *out)
21962306a36Sopenharmony_ci{
22062306a36Sopenharmony_ci	static const double color_ratios[3] = {75.0, 50.0, 20.0};
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	print_ratio(config, evsel, aggr_idx, stalled, out, STAT_CYCLES, color_ratios,
22362306a36Sopenharmony_ci		    "backend cycles idle");
22462306a36Sopenharmony_ci}
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_cistatic void print_branch_miss(struct perf_stat_config *config,
22762306a36Sopenharmony_ci			const struct evsel *evsel,
22862306a36Sopenharmony_ci			int aggr_idx, double misses,
22962306a36Sopenharmony_ci			struct perf_stat_output_ctx *out)
23062306a36Sopenharmony_ci{
23162306a36Sopenharmony_ci	static const double color_ratios[3] = {20.0, 10.0, 5.0};
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ci	print_ratio(config, evsel, aggr_idx, misses, out, STAT_BRANCHES, color_ratios,
23462306a36Sopenharmony_ci		    "of all branches");
23562306a36Sopenharmony_ci}
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic void print_l1d_miss(struct perf_stat_config *config,
23862306a36Sopenharmony_ci			const struct evsel *evsel,
23962306a36Sopenharmony_ci			int aggr_idx, double misses,
24062306a36Sopenharmony_ci			struct perf_stat_output_ctx *out)
24162306a36Sopenharmony_ci{
24262306a36Sopenharmony_ci	static const double color_ratios[3] = {20.0, 10.0, 5.0};
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	print_ratio(config, evsel, aggr_idx, misses, out, STAT_L1_DCACHE, color_ratios,
24562306a36Sopenharmony_ci		    "of all L1-dcache accesses");
24662306a36Sopenharmony_ci}
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_cistatic void print_l1i_miss(struct perf_stat_config *config,
24962306a36Sopenharmony_ci			const struct evsel *evsel,
25062306a36Sopenharmony_ci			int aggr_idx, double misses,
25162306a36Sopenharmony_ci			struct perf_stat_output_ctx *out)
25262306a36Sopenharmony_ci{
25362306a36Sopenharmony_ci	static const double color_ratios[3] = {20.0, 10.0, 5.0};
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci	print_ratio(config, evsel, aggr_idx, misses, out, STAT_L1_ICACHE, color_ratios,
25662306a36Sopenharmony_ci		    "of all L1-icache accesses");
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_cistatic void print_ll_miss(struct perf_stat_config *config,
26062306a36Sopenharmony_ci			const struct evsel *evsel,
26162306a36Sopenharmony_ci			int aggr_idx, double misses,
26262306a36Sopenharmony_ci			struct perf_stat_output_ctx *out)
26362306a36Sopenharmony_ci{
26462306a36Sopenharmony_ci	static const double color_ratios[3] = {20.0, 10.0, 5.0};
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	print_ratio(config, evsel, aggr_idx, misses, out, STAT_LL_CACHE, color_ratios,
26762306a36Sopenharmony_ci		    "of all LL-cache accesses");
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_cistatic void print_dtlb_miss(struct perf_stat_config *config,
27162306a36Sopenharmony_ci			const struct evsel *evsel,
27262306a36Sopenharmony_ci			int aggr_idx, double misses,
27362306a36Sopenharmony_ci			struct perf_stat_output_ctx *out)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	static const double color_ratios[3] = {20.0, 10.0, 5.0};
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	print_ratio(config, evsel, aggr_idx, misses, out, STAT_DTLB_CACHE, color_ratios,
27862306a36Sopenharmony_ci		    "of all dTLB cache accesses");
27962306a36Sopenharmony_ci}
28062306a36Sopenharmony_ci
28162306a36Sopenharmony_cistatic void print_itlb_miss(struct perf_stat_config *config,
28262306a36Sopenharmony_ci			const struct evsel *evsel,
28362306a36Sopenharmony_ci			int aggr_idx, double misses,
28462306a36Sopenharmony_ci			struct perf_stat_output_ctx *out)
28562306a36Sopenharmony_ci{
28662306a36Sopenharmony_ci	static const double color_ratios[3] = {20.0, 10.0, 5.0};
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ci	print_ratio(config, evsel, aggr_idx, misses, out, STAT_ITLB_CACHE, color_ratios,
28962306a36Sopenharmony_ci		    "of all iTLB cache accesses");
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_cistatic void print_cache_miss(struct perf_stat_config *config,
29362306a36Sopenharmony_ci			const struct evsel *evsel,
29462306a36Sopenharmony_ci			int aggr_idx, double misses,
29562306a36Sopenharmony_ci			struct perf_stat_output_ctx *out)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	static const double color_ratios[3] = {20.0, 10.0, 5.0};
29862306a36Sopenharmony_ci
29962306a36Sopenharmony_ci	print_ratio(config, evsel, aggr_idx, misses, out, STAT_CACHE_REFS, color_ratios,
30062306a36Sopenharmony_ci		    "of all cache refs");
30162306a36Sopenharmony_ci}
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_cistatic void print_instructions(struct perf_stat_config *config,
30462306a36Sopenharmony_ci			const struct evsel *evsel,
30562306a36Sopenharmony_ci			int aggr_idx, double instructions,
30662306a36Sopenharmony_ci			struct perf_stat_output_ctx *out)
30762306a36Sopenharmony_ci{
30862306a36Sopenharmony_ci	print_metric_t print_metric = out->print_metric;
30962306a36Sopenharmony_ci	void *ctxp = out->ctx;
31062306a36Sopenharmony_ci	double cycles = find_stat(evsel, aggr_idx, STAT_CYCLES);
31162306a36Sopenharmony_ci	double max_stalled = max(find_stat(evsel, aggr_idx, STAT_STALLED_CYCLES_FRONT),
31262306a36Sopenharmony_ci				find_stat(evsel, aggr_idx, STAT_STALLED_CYCLES_BACK));
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	if (cycles) {
31562306a36Sopenharmony_ci		print_metric(config, ctxp, NULL, "%7.2f ", "insn per cycle",
31662306a36Sopenharmony_ci			instructions / cycles);
31762306a36Sopenharmony_ci	} else
31862306a36Sopenharmony_ci		print_metric(config, ctxp, NULL, NULL, "insn per cycle", 0);
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	if (max_stalled && instructions) {
32162306a36Sopenharmony_ci		out->new_line(config, ctxp);
32262306a36Sopenharmony_ci		print_metric(config, ctxp, NULL, "%7.2f ", "stalled cycles per insn",
32362306a36Sopenharmony_ci			max_stalled / instructions);
32462306a36Sopenharmony_ci	}
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_cistatic void print_cycles(struct perf_stat_config *config,
32862306a36Sopenharmony_ci			const struct evsel *evsel,
32962306a36Sopenharmony_ci			int aggr_idx, double cycles,
33062306a36Sopenharmony_ci			struct perf_stat_output_ctx *out)
33162306a36Sopenharmony_ci{
33262306a36Sopenharmony_ci	double nsecs = find_stat(evsel, aggr_idx, STAT_NSECS);
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_ci	if (cycles && nsecs) {
33562306a36Sopenharmony_ci		double ratio = cycles / nsecs;
33662306a36Sopenharmony_ci
33762306a36Sopenharmony_ci		out->print_metric(config, out->ctx, NULL, "%8.3f", "GHz", ratio);
33862306a36Sopenharmony_ci	} else
33962306a36Sopenharmony_ci		out->print_metric(config, out->ctx, NULL, NULL, "GHz", 0);
34062306a36Sopenharmony_ci}
34162306a36Sopenharmony_ci
34262306a36Sopenharmony_cistatic void print_nsecs(struct perf_stat_config *config,
34362306a36Sopenharmony_ci			const struct evsel *evsel,
34462306a36Sopenharmony_ci			int aggr_idx __maybe_unused, double nsecs,
34562306a36Sopenharmony_ci			struct perf_stat_output_ctx *out)
34662306a36Sopenharmony_ci{
34762306a36Sopenharmony_ci	print_metric_t print_metric = out->print_metric;
34862306a36Sopenharmony_ci	void *ctxp = out->ctx;
34962306a36Sopenharmony_ci	double wall_time = avg_stats(&walltime_nsecs_stats);
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (wall_time) {
35262306a36Sopenharmony_ci		print_metric(config, ctxp, NULL, "%8.3f", "CPUs utilized",
35362306a36Sopenharmony_ci			nsecs / (wall_time * evsel->scale));
35462306a36Sopenharmony_ci	} else
35562306a36Sopenharmony_ci		print_metric(config, ctxp, NULL, NULL, "CPUs utilized", 0);
35662306a36Sopenharmony_ci}
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_cistatic int prepare_metric(struct evsel **metric_events,
35962306a36Sopenharmony_ci			  struct metric_ref *metric_refs,
36062306a36Sopenharmony_ci			  struct expr_parse_ctx *pctx,
36162306a36Sopenharmony_ci			  int aggr_idx)
36262306a36Sopenharmony_ci{
36362306a36Sopenharmony_ci	int i;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	for (i = 0; metric_events[i]; i++) {
36662306a36Sopenharmony_ci		char *n;
36762306a36Sopenharmony_ci		double val;
36862306a36Sopenharmony_ci		int source_count = 0;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci		if (evsel__is_tool(metric_events[i])) {
37162306a36Sopenharmony_ci			struct stats *stats;
37262306a36Sopenharmony_ci			double scale;
37362306a36Sopenharmony_ci
37462306a36Sopenharmony_ci			switch (metric_events[i]->tool_event) {
37562306a36Sopenharmony_ci			case PERF_TOOL_DURATION_TIME:
37662306a36Sopenharmony_ci				stats = &walltime_nsecs_stats;
37762306a36Sopenharmony_ci				scale = 1e-9;
37862306a36Sopenharmony_ci				break;
37962306a36Sopenharmony_ci			case PERF_TOOL_USER_TIME:
38062306a36Sopenharmony_ci				stats = &ru_stats.ru_utime_usec_stat;
38162306a36Sopenharmony_ci				scale = 1e-6;
38262306a36Sopenharmony_ci				break;
38362306a36Sopenharmony_ci			case PERF_TOOL_SYSTEM_TIME:
38462306a36Sopenharmony_ci				stats = &ru_stats.ru_stime_usec_stat;
38562306a36Sopenharmony_ci				scale = 1e-6;
38662306a36Sopenharmony_ci				break;
38762306a36Sopenharmony_ci			case PERF_TOOL_NONE:
38862306a36Sopenharmony_ci				pr_err("Invalid tool event 'none'");
38962306a36Sopenharmony_ci				abort();
39062306a36Sopenharmony_ci			case PERF_TOOL_MAX:
39162306a36Sopenharmony_ci				pr_err("Invalid tool event 'max'");
39262306a36Sopenharmony_ci				abort();
39362306a36Sopenharmony_ci			default:
39462306a36Sopenharmony_ci				pr_err("Unknown tool event '%s'", evsel__name(metric_events[i]));
39562306a36Sopenharmony_ci				abort();
39662306a36Sopenharmony_ci			}
39762306a36Sopenharmony_ci			val = avg_stats(stats) * scale;
39862306a36Sopenharmony_ci			source_count = 1;
39962306a36Sopenharmony_ci		} else {
40062306a36Sopenharmony_ci			struct perf_stat_evsel *ps = metric_events[i]->stats;
40162306a36Sopenharmony_ci			struct perf_stat_aggr *aggr = &ps->aggr[aggr_idx];
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci			if (!aggr)
40462306a36Sopenharmony_ci				break;
40562306a36Sopenharmony_ci
40662306a36Sopenharmony_ci                        if (!metric_events[i]->supported) {
40762306a36Sopenharmony_ci				/*
40862306a36Sopenharmony_ci				 * Not supported events will have a count of 0,
40962306a36Sopenharmony_ci				 * which can be confusing in a
41062306a36Sopenharmony_ci				 * metric. Explicitly set the value to NAN. Not
41162306a36Sopenharmony_ci				 * counted events (enable time of 0) are read as
41262306a36Sopenharmony_ci				 * 0.
41362306a36Sopenharmony_ci				 */
41462306a36Sopenharmony_ci				val = NAN;
41562306a36Sopenharmony_ci				source_count = 0;
41662306a36Sopenharmony_ci			} else {
41762306a36Sopenharmony_ci				val = aggr->counts.val;
41862306a36Sopenharmony_ci				source_count = evsel__source_count(metric_events[i]);
41962306a36Sopenharmony_ci			}
42062306a36Sopenharmony_ci		}
42162306a36Sopenharmony_ci		n = strdup(evsel__metric_id(metric_events[i]));
42262306a36Sopenharmony_ci		if (!n)
42362306a36Sopenharmony_ci			return -ENOMEM;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci		expr__add_id_val_source_count(pctx, n, val, source_count);
42662306a36Sopenharmony_ci	}
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	for (int j = 0; metric_refs && metric_refs[j].metric_name; j++) {
42962306a36Sopenharmony_ci		int ret = expr__add_ref(pctx, &metric_refs[j]);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci		if (ret)
43262306a36Sopenharmony_ci			return ret;
43362306a36Sopenharmony_ci	}
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	return i;
43662306a36Sopenharmony_ci}
43762306a36Sopenharmony_ci
43862306a36Sopenharmony_cistatic void generic_metric(struct perf_stat_config *config,
43962306a36Sopenharmony_ci			   const char *metric_expr,
44062306a36Sopenharmony_ci			   const char *metric_threshold,
44162306a36Sopenharmony_ci			   struct evsel **metric_events,
44262306a36Sopenharmony_ci			   struct metric_ref *metric_refs,
44362306a36Sopenharmony_ci			   char *name,
44462306a36Sopenharmony_ci			   const char *metric_name,
44562306a36Sopenharmony_ci			   const char *metric_unit,
44662306a36Sopenharmony_ci			   int runtime,
44762306a36Sopenharmony_ci			   int aggr_idx,
44862306a36Sopenharmony_ci			   struct perf_stat_output_ctx *out)
44962306a36Sopenharmony_ci{
45062306a36Sopenharmony_ci	print_metric_t print_metric = out->print_metric;
45162306a36Sopenharmony_ci	struct expr_parse_ctx *pctx;
45262306a36Sopenharmony_ci	double ratio, scale, threshold;
45362306a36Sopenharmony_ci	int i;
45462306a36Sopenharmony_ci	void *ctxp = out->ctx;
45562306a36Sopenharmony_ci	const char *color = NULL;
45662306a36Sopenharmony_ci
45762306a36Sopenharmony_ci	pctx = expr__ctx_new();
45862306a36Sopenharmony_ci	if (!pctx)
45962306a36Sopenharmony_ci		return;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	if (config->user_requested_cpu_list)
46262306a36Sopenharmony_ci		pctx->sctx.user_requested_cpu_list = strdup(config->user_requested_cpu_list);
46362306a36Sopenharmony_ci	pctx->sctx.runtime = runtime;
46462306a36Sopenharmony_ci	pctx->sctx.system_wide = config->system_wide;
46562306a36Sopenharmony_ci	i = prepare_metric(metric_events, metric_refs, pctx, aggr_idx);
46662306a36Sopenharmony_ci	if (i < 0) {
46762306a36Sopenharmony_ci		expr__ctx_free(pctx);
46862306a36Sopenharmony_ci		return;
46962306a36Sopenharmony_ci	}
47062306a36Sopenharmony_ci	if (!metric_events[i]) {
47162306a36Sopenharmony_ci		if (expr__parse(&ratio, pctx, metric_expr) == 0) {
47262306a36Sopenharmony_ci			char *unit;
47362306a36Sopenharmony_ci			char metric_bf[64];
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci			if (metric_threshold &&
47662306a36Sopenharmony_ci			    expr__parse(&threshold, pctx, metric_threshold) == 0 &&
47762306a36Sopenharmony_ci			    !isnan(threshold)) {
47862306a36Sopenharmony_ci				color = fpclassify(threshold) == FP_ZERO
47962306a36Sopenharmony_ci					? PERF_COLOR_GREEN : PERF_COLOR_RED;
48062306a36Sopenharmony_ci			}
48162306a36Sopenharmony_ci
48262306a36Sopenharmony_ci			if (metric_unit && metric_name) {
48362306a36Sopenharmony_ci				if (perf_pmu__convert_scale(metric_unit,
48462306a36Sopenharmony_ci					&unit, &scale) >= 0) {
48562306a36Sopenharmony_ci					ratio *= scale;
48662306a36Sopenharmony_ci				}
48762306a36Sopenharmony_ci				if (strstr(metric_expr, "?"))
48862306a36Sopenharmony_ci					scnprintf(metric_bf, sizeof(metric_bf),
48962306a36Sopenharmony_ci					  "%s  %s_%d", unit, metric_name, runtime);
49062306a36Sopenharmony_ci				else
49162306a36Sopenharmony_ci					scnprintf(metric_bf, sizeof(metric_bf),
49262306a36Sopenharmony_ci					  "%s  %s", unit, metric_name);
49362306a36Sopenharmony_ci
49462306a36Sopenharmony_ci				print_metric(config, ctxp, color, "%8.1f",
49562306a36Sopenharmony_ci					     metric_bf, ratio);
49662306a36Sopenharmony_ci			} else {
49762306a36Sopenharmony_ci				print_metric(config, ctxp, color, "%8.2f",
49862306a36Sopenharmony_ci					metric_name ?
49962306a36Sopenharmony_ci					metric_name :
50062306a36Sopenharmony_ci					out->force_header ?  name : "",
50162306a36Sopenharmony_ci					ratio);
50262306a36Sopenharmony_ci			}
50362306a36Sopenharmony_ci		} else {
50462306a36Sopenharmony_ci			print_metric(config, ctxp, color, /*unit=*/NULL,
50562306a36Sopenharmony_ci				     out->force_header ?
50662306a36Sopenharmony_ci				     (metric_name ? metric_name : name) : "", 0);
50762306a36Sopenharmony_ci		}
50862306a36Sopenharmony_ci	} else {
50962306a36Sopenharmony_ci		print_metric(config, ctxp, color, /*unit=*/NULL,
51062306a36Sopenharmony_ci			     out->force_header ?
51162306a36Sopenharmony_ci			     (metric_name ? metric_name : name) : "", 0);
51262306a36Sopenharmony_ci	}
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	expr__ctx_free(pctx);
51562306a36Sopenharmony_ci}
51662306a36Sopenharmony_ci
51762306a36Sopenharmony_cidouble test_generic_metric(struct metric_expr *mexp, int aggr_idx)
51862306a36Sopenharmony_ci{
51962306a36Sopenharmony_ci	struct expr_parse_ctx *pctx;
52062306a36Sopenharmony_ci	double ratio = 0.0;
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	pctx = expr__ctx_new();
52362306a36Sopenharmony_ci	if (!pctx)
52462306a36Sopenharmony_ci		return NAN;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	if (prepare_metric(mexp->metric_events, mexp->metric_refs, pctx, aggr_idx) < 0)
52762306a36Sopenharmony_ci		goto out;
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_ci	if (expr__parse(&ratio, pctx, mexp->metric_expr))
53062306a36Sopenharmony_ci		ratio = 0.0;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ciout:
53362306a36Sopenharmony_ci	expr__ctx_free(pctx);
53462306a36Sopenharmony_ci	return ratio;
53562306a36Sopenharmony_ci}
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_cistatic void perf_stat__print_metricgroup_header(struct perf_stat_config *config,
53862306a36Sopenharmony_ci						struct evsel *evsel,
53962306a36Sopenharmony_ci						void *ctxp,
54062306a36Sopenharmony_ci						const char *name,
54162306a36Sopenharmony_ci						struct perf_stat_output_ctx *out)
54262306a36Sopenharmony_ci{
54362306a36Sopenharmony_ci	bool need_full_name = perf_pmus__num_core_pmus() > 1;
54462306a36Sopenharmony_ci	static const char *last_name;
54562306a36Sopenharmony_ci	static const char *last_pmu;
54662306a36Sopenharmony_ci	char full_name[64];
54762306a36Sopenharmony_ci
54862306a36Sopenharmony_ci	/*
54962306a36Sopenharmony_ci	 * A metricgroup may have several metric events,
55062306a36Sopenharmony_ci	 * e.g.,TopdownL1 on e-core of ADL.
55162306a36Sopenharmony_ci	 * The name has been output by the first metric
55262306a36Sopenharmony_ci	 * event. Only align with other metics from
55362306a36Sopenharmony_ci	 * different metric events.
55462306a36Sopenharmony_ci	 */
55562306a36Sopenharmony_ci	if (last_name && !strcmp(last_name, name)) {
55662306a36Sopenharmony_ci		if (!need_full_name || !strcmp(last_pmu, evsel->pmu_name)) {
55762306a36Sopenharmony_ci			out->print_metricgroup_header(config, ctxp, NULL);
55862306a36Sopenharmony_ci			return;
55962306a36Sopenharmony_ci		}
56062306a36Sopenharmony_ci	}
56162306a36Sopenharmony_ci
56262306a36Sopenharmony_ci	if (need_full_name)
56362306a36Sopenharmony_ci		scnprintf(full_name, sizeof(full_name), "%s (%s)", name, evsel->pmu_name);
56462306a36Sopenharmony_ci	else
56562306a36Sopenharmony_ci		scnprintf(full_name, sizeof(full_name), "%s", name);
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	out->print_metricgroup_header(config, ctxp, full_name);
56862306a36Sopenharmony_ci
56962306a36Sopenharmony_ci	last_name = name;
57062306a36Sopenharmony_ci	last_pmu = evsel->pmu_name;
57162306a36Sopenharmony_ci}
57262306a36Sopenharmony_ci
57362306a36Sopenharmony_ci/**
57462306a36Sopenharmony_ci * perf_stat__print_shadow_stats_metricgroup - Print out metrics associated with the evsel
57562306a36Sopenharmony_ci *					       For the non-default, all metrics associated
57662306a36Sopenharmony_ci *					       with the evsel are printed.
57762306a36Sopenharmony_ci *					       For the default mode, only the metrics from
57862306a36Sopenharmony_ci *					       the same metricgroup and the name of the
57962306a36Sopenharmony_ci *					       metricgroup are printed. To print the metrics
58062306a36Sopenharmony_ci *					       from the next metricgroup (if available),
58162306a36Sopenharmony_ci *					       invoke the function with correspoinding
58262306a36Sopenharmony_ci *					       metric_expr.
58362306a36Sopenharmony_ci */
58462306a36Sopenharmony_civoid *perf_stat__print_shadow_stats_metricgroup(struct perf_stat_config *config,
58562306a36Sopenharmony_ci						struct evsel *evsel,
58662306a36Sopenharmony_ci						int aggr_idx,
58762306a36Sopenharmony_ci						int *num,
58862306a36Sopenharmony_ci						void *from,
58962306a36Sopenharmony_ci						struct perf_stat_output_ctx *out,
59062306a36Sopenharmony_ci						struct rblist *metric_events)
59162306a36Sopenharmony_ci{
59262306a36Sopenharmony_ci	struct metric_event *me;
59362306a36Sopenharmony_ci	struct metric_expr *mexp = from;
59462306a36Sopenharmony_ci	void *ctxp = out->ctx;
59562306a36Sopenharmony_ci	bool header_printed = false;
59662306a36Sopenharmony_ci	const char *name = NULL;
59762306a36Sopenharmony_ci
59862306a36Sopenharmony_ci	me = metricgroup__lookup(metric_events, evsel, false);
59962306a36Sopenharmony_ci	if (me == NULL)
60062306a36Sopenharmony_ci		return NULL;
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ci	if (!mexp)
60362306a36Sopenharmony_ci		mexp = list_first_entry(&me->head, typeof(*mexp), nd);
60462306a36Sopenharmony_ci
60562306a36Sopenharmony_ci	list_for_each_entry_from(mexp, &me->head, nd) {
60662306a36Sopenharmony_ci		/* Print the display name of the Default metricgroup */
60762306a36Sopenharmony_ci		if (!config->metric_only && me->is_default) {
60862306a36Sopenharmony_ci			if (!name)
60962306a36Sopenharmony_ci				name = mexp->default_metricgroup_name;
61062306a36Sopenharmony_ci			/*
61162306a36Sopenharmony_ci			 * Two or more metricgroup may share the same metric
61262306a36Sopenharmony_ci			 * event, e.g., TopdownL1 and TopdownL2 on SPR.
61362306a36Sopenharmony_ci			 * Return and print the prefix, e.g., noise, running
61462306a36Sopenharmony_ci			 * for the next metricgroup.
61562306a36Sopenharmony_ci			 */
61662306a36Sopenharmony_ci			if (strcmp(name, mexp->default_metricgroup_name))
61762306a36Sopenharmony_ci				return (void *)mexp;
61862306a36Sopenharmony_ci			/* Only print the name of the metricgroup once */
61962306a36Sopenharmony_ci			if (!header_printed) {
62062306a36Sopenharmony_ci				header_printed = true;
62162306a36Sopenharmony_ci				perf_stat__print_metricgroup_header(config, evsel, ctxp,
62262306a36Sopenharmony_ci								    name, out);
62362306a36Sopenharmony_ci			}
62462306a36Sopenharmony_ci		}
62562306a36Sopenharmony_ci
62662306a36Sopenharmony_ci		if ((*num)++ > 0)
62762306a36Sopenharmony_ci			out->new_line(config, ctxp);
62862306a36Sopenharmony_ci		generic_metric(config, mexp->metric_expr, mexp->metric_threshold,
62962306a36Sopenharmony_ci			       mexp->metric_events, mexp->metric_refs, evsel->name,
63062306a36Sopenharmony_ci			       mexp->metric_name, mexp->metric_unit, mexp->runtime,
63162306a36Sopenharmony_ci			       aggr_idx, out);
63262306a36Sopenharmony_ci	}
63362306a36Sopenharmony_ci
63462306a36Sopenharmony_ci	return NULL;
63562306a36Sopenharmony_ci}
63662306a36Sopenharmony_ci
63762306a36Sopenharmony_civoid perf_stat__print_shadow_stats(struct perf_stat_config *config,
63862306a36Sopenharmony_ci				   struct evsel *evsel,
63962306a36Sopenharmony_ci				   double avg, int aggr_idx,
64062306a36Sopenharmony_ci				   struct perf_stat_output_ctx *out,
64162306a36Sopenharmony_ci				   struct rblist *metric_events)
64262306a36Sopenharmony_ci{
64362306a36Sopenharmony_ci	typedef void (*stat_print_function_t)(struct perf_stat_config *config,
64462306a36Sopenharmony_ci					const struct evsel *evsel,
64562306a36Sopenharmony_ci					int aggr_idx, double misses,
64662306a36Sopenharmony_ci					struct perf_stat_output_ctx *out);
64762306a36Sopenharmony_ci	static const stat_print_function_t stat_print_function[STAT_MAX] = {
64862306a36Sopenharmony_ci		[STAT_INSTRUCTIONS] = print_instructions,
64962306a36Sopenharmony_ci		[STAT_BRANCH_MISS] = print_branch_miss,
65062306a36Sopenharmony_ci		[STAT_L1D_MISS] = print_l1d_miss,
65162306a36Sopenharmony_ci		[STAT_L1I_MISS] = print_l1i_miss,
65262306a36Sopenharmony_ci		[STAT_DTLB_MISS] = print_dtlb_miss,
65362306a36Sopenharmony_ci		[STAT_ITLB_MISS] = print_itlb_miss,
65462306a36Sopenharmony_ci		[STAT_LL_MISS] = print_ll_miss,
65562306a36Sopenharmony_ci		[STAT_CACHE_MISSES] = print_cache_miss,
65662306a36Sopenharmony_ci		[STAT_STALLED_CYCLES_FRONT] = print_stalled_cycles_front,
65762306a36Sopenharmony_ci		[STAT_STALLED_CYCLES_BACK] = print_stalled_cycles_back,
65862306a36Sopenharmony_ci		[STAT_CYCLES] = print_cycles,
65962306a36Sopenharmony_ci		[STAT_NSECS] = print_nsecs,
66062306a36Sopenharmony_ci	};
66162306a36Sopenharmony_ci	print_metric_t print_metric = out->print_metric;
66262306a36Sopenharmony_ci	void *ctxp = out->ctx;
66362306a36Sopenharmony_ci	int num = 1;
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_ci	if (config->iostat_run) {
66662306a36Sopenharmony_ci		iostat_print_metric(config, evsel, out);
66762306a36Sopenharmony_ci	} else {
66862306a36Sopenharmony_ci		stat_print_function_t fn = stat_print_function[evsel__stat_type(evsel)];
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci		if (fn)
67162306a36Sopenharmony_ci			fn(config, evsel, aggr_idx, avg, out);
67262306a36Sopenharmony_ci		else {
67362306a36Sopenharmony_ci			double nsecs =	find_stat(evsel, aggr_idx, STAT_NSECS);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci			if (nsecs) {
67662306a36Sopenharmony_ci				char unit = ' ';
67762306a36Sopenharmony_ci				char unit_buf[10] = "/sec";
67862306a36Sopenharmony_ci				double ratio = convert_unit_double(1000000000.0 * avg / nsecs,
67962306a36Sopenharmony_ci								   &unit);
68062306a36Sopenharmony_ci
68162306a36Sopenharmony_ci				if (unit != ' ')
68262306a36Sopenharmony_ci					snprintf(unit_buf, sizeof(unit_buf), "%c/sec", unit);
68362306a36Sopenharmony_ci				print_metric(config, ctxp, NULL, "%8.3f", unit_buf, ratio);
68462306a36Sopenharmony_ci			} else
68562306a36Sopenharmony_ci				num = 0;
68662306a36Sopenharmony_ci		}
68762306a36Sopenharmony_ci	}
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	perf_stat__print_shadow_stats_metricgroup(config, evsel, aggr_idx,
69062306a36Sopenharmony_ci						  &num, NULL, out, metric_events);
69162306a36Sopenharmony_ci
69262306a36Sopenharmony_ci	if (num == 0)
69362306a36Sopenharmony_ci		print_metric(config, ctxp, NULL, NULL, NULL, 0);
69462306a36Sopenharmony_ci}
69562306a36Sopenharmony_ci
69662306a36Sopenharmony_ci/**
69762306a36Sopenharmony_ci * perf_stat__skip_metric_event - Skip the evsel in the Default metricgroup,
69862306a36Sopenharmony_ci *				  if it's not running or not the metric event.
69962306a36Sopenharmony_ci */
70062306a36Sopenharmony_cibool perf_stat__skip_metric_event(struct evsel *evsel,
70162306a36Sopenharmony_ci				  struct rblist *metric_events,
70262306a36Sopenharmony_ci				  u64 ena, u64 run)
70362306a36Sopenharmony_ci{
70462306a36Sopenharmony_ci	if (!evsel->default_metricgroup)
70562306a36Sopenharmony_ci		return false;
70662306a36Sopenharmony_ci
70762306a36Sopenharmony_ci	if (!ena || !run)
70862306a36Sopenharmony_ci		return true;
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ci	return !metricgroup__lookup(metric_events, evsel, false);
71162306a36Sopenharmony_ci}
712