18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci#include "math.h"
38c2ecf20Sopenharmony_ci#include "parse-events.h"
48c2ecf20Sopenharmony_ci#include "pmu.h"
58c2ecf20Sopenharmony_ci#include "tests.h"
68c2ecf20Sopenharmony_ci#include <errno.h>
78c2ecf20Sopenharmony_ci#include <stdio.h>
88c2ecf20Sopenharmony_ci#include <linux/kernel.h>
98c2ecf20Sopenharmony_ci#include <linux/zalloc.h>
108c2ecf20Sopenharmony_ci#include "debug.h"
118c2ecf20Sopenharmony_ci#include "../pmu-events/pmu-events.h"
128c2ecf20Sopenharmony_ci#include "util/evlist.h"
138c2ecf20Sopenharmony_ci#include "util/expr.h"
148c2ecf20Sopenharmony_ci#include "util/parse-events.h"
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_cistruct perf_pmu_test_event {
178c2ecf20Sopenharmony_ci	struct pmu_event event;
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci	/* extra events for aliases */
208c2ecf20Sopenharmony_ci	const char *alias_str;
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci	/*
238c2ecf20Sopenharmony_ci	 * Note: For when PublicDescription does not exist in the JSON, we
248c2ecf20Sopenharmony_ci	 * will have no long_desc in pmu_event.long_desc, but long_desc may
258c2ecf20Sopenharmony_ci	 * be set in the alias.
268c2ecf20Sopenharmony_ci	 */
278c2ecf20Sopenharmony_ci	const char *alias_long_desc;
288c2ecf20Sopenharmony_ci};
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic struct perf_pmu_test_event test_cpu_events[] = {
318c2ecf20Sopenharmony_ci	{
328c2ecf20Sopenharmony_ci		.event = {
338c2ecf20Sopenharmony_ci			.name = "bp_l1_btb_correct",
348c2ecf20Sopenharmony_ci			.event = "event=0x8a",
358c2ecf20Sopenharmony_ci			.desc = "L1 BTB Correction",
368c2ecf20Sopenharmony_ci			.topic = "branch",
378c2ecf20Sopenharmony_ci		},
388c2ecf20Sopenharmony_ci		.alias_str = "event=0x8a",
398c2ecf20Sopenharmony_ci		.alias_long_desc = "L1 BTB Correction",
408c2ecf20Sopenharmony_ci	},
418c2ecf20Sopenharmony_ci	{
428c2ecf20Sopenharmony_ci		.event = {
438c2ecf20Sopenharmony_ci			.name = "bp_l2_btb_correct",
448c2ecf20Sopenharmony_ci			.event = "event=0x8b",
458c2ecf20Sopenharmony_ci			.desc = "L2 BTB Correction",
468c2ecf20Sopenharmony_ci			.topic = "branch",
478c2ecf20Sopenharmony_ci		},
488c2ecf20Sopenharmony_ci		.alias_str = "event=0x8b",
498c2ecf20Sopenharmony_ci		.alias_long_desc = "L2 BTB Correction",
508c2ecf20Sopenharmony_ci	},
518c2ecf20Sopenharmony_ci	{
528c2ecf20Sopenharmony_ci		.event = {
538c2ecf20Sopenharmony_ci			.name = "segment_reg_loads.any",
548c2ecf20Sopenharmony_ci			.event = "umask=0x80,period=200000,event=0x6",
558c2ecf20Sopenharmony_ci			.desc = "Number of segment register loads",
568c2ecf20Sopenharmony_ci			.topic = "other",
578c2ecf20Sopenharmony_ci		},
588c2ecf20Sopenharmony_ci		.alias_str = "umask=0x80,(null)=0x30d40,event=0x6",
598c2ecf20Sopenharmony_ci		.alias_long_desc = "Number of segment register loads",
608c2ecf20Sopenharmony_ci	},
618c2ecf20Sopenharmony_ci	{
628c2ecf20Sopenharmony_ci		.event = {
638c2ecf20Sopenharmony_ci			.name = "dispatch_blocked.any",
648c2ecf20Sopenharmony_ci			.event = "umask=0x20,period=200000,event=0x9",
658c2ecf20Sopenharmony_ci			.desc = "Memory cluster signals to block micro-op dispatch for any reason",
668c2ecf20Sopenharmony_ci			.topic = "other",
678c2ecf20Sopenharmony_ci		},
688c2ecf20Sopenharmony_ci		.alias_str = "umask=0x20,(null)=0x30d40,event=0x9",
698c2ecf20Sopenharmony_ci		.alias_long_desc = "Memory cluster signals to block micro-op dispatch for any reason",
708c2ecf20Sopenharmony_ci	},
718c2ecf20Sopenharmony_ci	{
728c2ecf20Sopenharmony_ci		.event = {
738c2ecf20Sopenharmony_ci			.name = "eist_trans",
748c2ecf20Sopenharmony_ci			.event = "umask=0x0,period=200000,event=0x3a",
758c2ecf20Sopenharmony_ci			.desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions",
768c2ecf20Sopenharmony_ci			.topic = "other",
778c2ecf20Sopenharmony_ci		},
788c2ecf20Sopenharmony_ci		.alias_str = "umask=0,(null)=0x30d40,event=0x3a",
798c2ecf20Sopenharmony_ci		.alias_long_desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions",
808c2ecf20Sopenharmony_ci	},
818c2ecf20Sopenharmony_ci	{ /* sentinel */
828c2ecf20Sopenharmony_ci		.event = {
838c2ecf20Sopenharmony_ci			.name = NULL,
848c2ecf20Sopenharmony_ci		},
858c2ecf20Sopenharmony_ci	},
868c2ecf20Sopenharmony_ci};
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic struct perf_pmu_test_event test_uncore_events[] = {
898c2ecf20Sopenharmony_ci	{
908c2ecf20Sopenharmony_ci		.event = {
918c2ecf20Sopenharmony_ci			.name = "uncore_hisi_ddrc.flux_wcmd",
928c2ecf20Sopenharmony_ci			.event = "event=0x2",
938c2ecf20Sopenharmony_ci			.desc = "DDRC write commands. Unit: hisi_sccl,ddrc ",
948c2ecf20Sopenharmony_ci			.topic = "uncore",
958c2ecf20Sopenharmony_ci			.long_desc = "DDRC write commands",
968c2ecf20Sopenharmony_ci			.pmu = "hisi_sccl,ddrc",
978c2ecf20Sopenharmony_ci		},
988c2ecf20Sopenharmony_ci		.alias_str = "event=0x2",
998c2ecf20Sopenharmony_ci		.alias_long_desc = "DDRC write commands",
1008c2ecf20Sopenharmony_ci	},
1018c2ecf20Sopenharmony_ci	{
1028c2ecf20Sopenharmony_ci		.event = {
1038c2ecf20Sopenharmony_ci			.name = "unc_cbo_xsnp_response.miss_eviction",
1048c2ecf20Sopenharmony_ci			.event = "umask=0x81,event=0x22",
1058c2ecf20Sopenharmony_ci			.desc = "Unit: uncore_cbox A cross-core snoop resulted from L3 Eviction which misses in some processor core",
1068c2ecf20Sopenharmony_ci			.topic = "uncore",
1078c2ecf20Sopenharmony_ci			.long_desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core",
1088c2ecf20Sopenharmony_ci			.pmu = "uncore_cbox",
1098c2ecf20Sopenharmony_ci		},
1108c2ecf20Sopenharmony_ci		.alias_str = "umask=0x81,event=0x22",
1118c2ecf20Sopenharmony_ci		.alias_long_desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core",
1128c2ecf20Sopenharmony_ci	},
1138c2ecf20Sopenharmony_ci	{ /* sentinel */
1148c2ecf20Sopenharmony_ci		.event = {
1158c2ecf20Sopenharmony_ci			.name = NULL,
1168c2ecf20Sopenharmony_ci		},
1178c2ecf20Sopenharmony_ci	}
1188c2ecf20Sopenharmony_ci};
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ciconst int total_test_events_size = ARRAY_SIZE(test_uncore_events);
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_cistatic bool is_same(const char *reference, const char *test)
1238c2ecf20Sopenharmony_ci{
1248c2ecf20Sopenharmony_ci	if (!reference && !test)
1258c2ecf20Sopenharmony_ci		return true;
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	if (reference && !test)
1288c2ecf20Sopenharmony_ci		return false;
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	if (!reference && test)
1318c2ecf20Sopenharmony_ci		return false;
1328c2ecf20Sopenharmony_ci
1338c2ecf20Sopenharmony_ci	return !strcmp(reference, test);
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic struct pmu_events_map *__test_pmu_get_events_map(void)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	struct pmu_events_map *map;
1398c2ecf20Sopenharmony_ci
1408c2ecf20Sopenharmony_ci	for (map = &pmu_events_map[0]; map->cpuid; map++) {
1418c2ecf20Sopenharmony_ci		if (!strcmp(map->cpuid, "testcpu"))
1428c2ecf20Sopenharmony_ci			return map;
1438c2ecf20Sopenharmony_ci	}
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	pr_err("could not find test events map\n");
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci	return NULL;
1488c2ecf20Sopenharmony_ci}
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci/* Verify generated events from pmu-events.c is as expected */
1518c2ecf20Sopenharmony_cistatic int test_pmu_event_table(void)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	struct pmu_events_map *map = __test_pmu_get_events_map();
1548c2ecf20Sopenharmony_ci	struct pmu_event *table;
1558c2ecf20Sopenharmony_ci	int map_events = 0, expected_events;
1568c2ecf20Sopenharmony_ci
1578c2ecf20Sopenharmony_ci	/* ignore 2x sentinels */
1588c2ecf20Sopenharmony_ci	expected_events = ARRAY_SIZE(test_cpu_events) +
1598c2ecf20Sopenharmony_ci			  ARRAY_SIZE(test_uncore_events) - 2;
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_ci	if (!map)
1628c2ecf20Sopenharmony_ci		return -1;
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_ci	for (table = map->table; table->name; table++) {
1658c2ecf20Sopenharmony_ci		struct perf_pmu_test_event *test;
1668c2ecf20Sopenharmony_ci		struct pmu_event *te;
1678c2ecf20Sopenharmony_ci		bool found = false;
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci		if (table->pmu)
1708c2ecf20Sopenharmony_ci			test = &test_uncore_events[0];
1718c2ecf20Sopenharmony_ci		else
1728c2ecf20Sopenharmony_ci			test = &test_cpu_events[0];
1738c2ecf20Sopenharmony_ci
1748c2ecf20Sopenharmony_ci		te = &test->event;
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci		for (; te->name; test++, te = &test->event) {
1778c2ecf20Sopenharmony_ci			if (strcmp(table->name, te->name))
1788c2ecf20Sopenharmony_ci				continue;
1798c2ecf20Sopenharmony_ci			found = true;
1808c2ecf20Sopenharmony_ci			map_events++;
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci			if (!is_same(table->desc, te->desc)) {
1838c2ecf20Sopenharmony_ci				pr_debug2("testing event table %s: mismatched desc, %s vs %s\n",
1848c2ecf20Sopenharmony_ci					  table->name, table->desc, te->desc);
1858c2ecf20Sopenharmony_ci				return -1;
1868c2ecf20Sopenharmony_ci			}
1878c2ecf20Sopenharmony_ci
1888c2ecf20Sopenharmony_ci			if (!is_same(table->topic, te->topic)) {
1898c2ecf20Sopenharmony_ci				pr_debug2("testing event table %s: mismatched topic, %s vs %s\n",
1908c2ecf20Sopenharmony_ci					  table->name, table->topic,
1918c2ecf20Sopenharmony_ci					  te->topic);
1928c2ecf20Sopenharmony_ci				return -1;
1938c2ecf20Sopenharmony_ci			}
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_ci			if (!is_same(table->long_desc, te->long_desc)) {
1968c2ecf20Sopenharmony_ci				pr_debug2("testing event table %s: mismatched long_desc, %s vs %s\n",
1978c2ecf20Sopenharmony_ci					  table->name, table->long_desc,
1988c2ecf20Sopenharmony_ci					  te->long_desc);
1998c2ecf20Sopenharmony_ci				return -1;
2008c2ecf20Sopenharmony_ci			}
2018c2ecf20Sopenharmony_ci
2028c2ecf20Sopenharmony_ci			if (!is_same(table->unit, te->unit)) {
2038c2ecf20Sopenharmony_ci				pr_debug2("testing event table %s: mismatched unit, %s vs %s\n",
2048c2ecf20Sopenharmony_ci					  table->name, table->unit,
2058c2ecf20Sopenharmony_ci					  te->unit);
2068c2ecf20Sopenharmony_ci				return -1;
2078c2ecf20Sopenharmony_ci			}
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_ci			if (!is_same(table->perpkg, te->perpkg)) {
2108c2ecf20Sopenharmony_ci				pr_debug2("testing event table %s: mismatched perpkg, %s vs %s\n",
2118c2ecf20Sopenharmony_ci					  table->name, table->perpkg,
2128c2ecf20Sopenharmony_ci					  te->perpkg);
2138c2ecf20Sopenharmony_ci				return -1;
2148c2ecf20Sopenharmony_ci			}
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_ci			if (!is_same(table->metric_expr, te->metric_expr)) {
2178c2ecf20Sopenharmony_ci				pr_debug2("testing event table %s: mismatched metric_expr, %s vs %s\n",
2188c2ecf20Sopenharmony_ci					  table->name, table->metric_expr,
2198c2ecf20Sopenharmony_ci					  te->metric_expr);
2208c2ecf20Sopenharmony_ci				return -1;
2218c2ecf20Sopenharmony_ci			}
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci			if (!is_same(table->metric_name, te->metric_name)) {
2248c2ecf20Sopenharmony_ci				pr_debug2("testing event table %s: mismatched metric_name, %s vs %s\n",
2258c2ecf20Sopenharmony_ci					  table->name,  table->metric_name,
2268c2ecf20Sopenharmony_ci					  te->metric_name);
2278c2ecf20Sopenharmony_ci				return -1;
2288c2ecf20Sopenharmony_ci			}
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci			if (!is_same(table->deprecated, te->deprecated)) {
2318c2ecf20Sopenharmony_ci				pr_debug2("testing event table %s: mismatched deprecated, %s vs %s\n",
2328c2ecf20Sopenharmony_ci					  table->name, table->deprecated,
2338c2ecf20Sopenharmony_ci					  te->deprecated);
2348c2ecf20Sopenharmony_ci				return -1;
2358c2ecf20Sopenharmony_ci			}
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci			pr_debug("testing event table %s: pass\n", table->name);
2388c2ecf20Sopenharmony_ci		}
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci		if (!found) {
2418c2ecf20Sopenharmony_ci			pr_err("testing event table: could not find event %s\n",
2428c2ecf20Sopenharmony_ci			       table->name);
2438c2ecf20Sopenharmony_ci			return -1;
2448c2ecf20Sopenharmony_ci		}
2458c2ecf20Sopenharmony_ci	}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci	if (map_events != expected_events) {
2488c2ecf20Sopenharmony_ci		pr_err("testing event table: found %d, but expected %d\n",
2498c2ecf20Sopenharmony_ci		       map_events, expected_events);
2508c2ecf20Sopenharmony_ci		return -1;
2518c2ecf20Sopenharmony_ci	}
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ci	return 0;
2548c2ecf20Sopenharmony_ci}
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic struct perf_pmu_alias *find_alias(const char *test_event, struct list_head *aliases)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	struct perf_pmu_alias *alias;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	list_for_each_entry(alias, aliases, list)
2618c2ecf20Sopenharmony_ci		if (!strcmp(test_event, alias->name))
2628c2ecf20Sopenharmony_ci			return alias;
2638c2ecf20Sopenharmony_ci
2648c2ecf20Sopenharmony_ci	return NULL;
2658c2ecf20Sopenharmony_ci}
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_ci/* Verify aliases are as expected */
2688c2ecf20Sopenharmony_cistatic int __test__pmu_event_aliases(char *pmu_name, int *count)
2698c2ecf20Sopenharmony_ci{
2708c2ecf20Sopenharmony_ci	struct perf_pmu_test_event *test;
2718c2ecf20Sopenharmony_ci	struct pmu_event *te;
2728c2ecf20Sopenharmony_ci	struct perf_pmu *pmu;
2738c2ecf20Sopenharmony_ci	LIST_HEAD(aliases);
2748c2ecf20Sopenharmony_ci	int res = 0;
2758c2ecf20Sopenharmony_ci	bool use_uncore_table;
2768c2ecf20Sopenharmony_ci	struct pmu_events_map *map = __test_pmu_get_events_map();
2778c2ecf20Sopenharmony_ci	struct perf_pmu_alias *a, *tmp;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	if (!map)
2808c2ecf20Sopenharmony_ci		return -1;
2818c2ecf20Sopenharmony_ci
2828c2ecf20Sopenharmony_ci	if (is_pmu_core(pmu_name)) {
2838c2ecf20Sopenharmony_ci		test = &test_cpu_events[0];
2848c2ecf20Sopenharmony_ci		use_uncore_table = false;
2858c2ecf20Sopenharmony_ci	} else {
2868c2ecf20Sopenharmony_ci		test = &test_uncore_events[0];
2878c2ecf20Sopenharmony_ci		use_uncore_table = true;
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci	pmu = zalloc(sizeof(*pmu));
2918c2ecf20Sopenharmony_ci	if (!pmu)
2928c2ecf20Sopenharmony_ci		return -1;
2938c2ecf20Sopenharmony_ci
2948c2ecf20Sopenharmony_ci	pmu->name = pmu_name;
2958c2ecf20Sopenharmony_ci
2968c2ecf20Sopenharmony_ci	pmu_add_cpu_aliases_map(&aliases, pmu, map);
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	for (te = &test->event; te->name; test++, te = &test->event) {
2998c2ecf20Sopenharmony_ci		struct perf_pmu_alias *alias = find_alias(te->name, &aliases);
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci		if (!alias) {
3028c2ecf20Sopenharmony_ci			bool uncore_match = pmu_uncore_alias_match(pmu_name,
3038c2ecf20Sopenharmony_ci								   te->pmu);
3048c2ecf20Sopenharmony_ci
3058c2ecf20Sopenharmony_ci			if (use_uncore_table && !uncore_match) {
3068c2ecf20Sopenharmony_ci				pr_debug3("testing aliases PMU %s: skip matching alias %s\n",
3078c2ecf20Sopenharmony_ci					  pmu_name, te->name);
3088c2ecf20Sopenharmony_ci				continue;
3098c2ecf20Sopenharmony_ci			}
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci			pr_debug2("testing aliases PMU %s: no alias, alias_table->name=%s\n",
3128c2ecf20Sopenharmony_ci				  pmu_name, te->name);
3138c2ecf20Sopenharmony_ci			res = -1;
3148c2ecf20Sopenharmony_ci			break;
3158c2ecf20Sopenharmony_ci		}
3168c2ecf20Sopenharmony_ci
3178c2ecf20Sopenharmony_ci		if (!is_same(alias->desc, te->desc)) {
3188c2ecf20Sopenharmony_ci			pr_debug2("testing aliases PMU %s: mismatched desc, %s vs %s\n",
3198c2ecf20Sopenharmony_ci				  pmu_name, alias->desc, te->desc);
3208c2ecf20Sopenharmony_ci			res = -1;
3218c2ecf20Sopenharmony_ci			break;
3228c2ecf20Sopenharmony_ci		}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci		if (!is_same(alias->long_desc, test->alias_long_desc)) {
3258c2ecf20Sopenharmony_ci			pr_debug2("testing aliases PMU %s: mismatched long_desc, %s vs %s\n",
3268c2ecf20Sopenharmony_ci				  pmu_name, alias->long_desc,
3278c2ecf20Sopenharmony_ci				  test->alias_long_desc);
3288c2ecf20Sopenharmony_ci			res = -1;
3298c2ecf20Sopenharmony_ci			break;
3308c2ecf20Sopenharmony_ci		}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci		if (!is_same(alias->str, test->alias_str)) {
3338c2ecf20Sopenharmony_ci			pr_debug2("testing aliases PMU %s: mismatched str, %s vs %s\n",
3348c2ecf20Sopenharmony_ci				  pmu_name, alias->str, test->alias_str);
3358c2ecf20Sopenharmony_ci			res = -1;
3368c2ecf20Sopenharmony_ci			break;
3378c2ecf20Sopenharmony_ci		}
3388c2ecf20Sopenharmony_ci
3398c2ecf20Sopenharmony_ci		if (!is_same(alias->topic, te->topic)) {
3408c2ecf20Sopenharmony_ci			pr_debug2("testing aliases PMU %s: mismatched topic, %s vs %s\n",
3418c2ecf20Sopenharmony_ci				  pmu_name, alias->topic, te->topic);
3428c2ecf20Sopenharmony_ci			res = -1;
3438c2ecf20Sopenharmony_ci			break;
3448c2ecf20Sopenharmony_ci		}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci		(*count)++;
3478c2ecf20Sopenharmony_ci		pr_debug2("testing aliases PMU %s: matched event %s\n",
3488c2ecf20Sopenharmony_ci			  pmu_name, alias->name);
3498c2ecf20Sopenharmony_ci	}
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	list_for_each_entry_safe(a, tmp, &aliases, list) {
3528c2ecf20Sopenharmony_ci		list_del(&a->list);
3538c2ecf20Sopenharmony_ci		perf_pmu_free_alias(a);
3548c2ecf20Sopenharmony_ci	}
3558c2ecf20Sopenharmony_ci	free(pmu);
3568c2ecf20Sopenharmony_ci	return res;
3578c2ecf20Sopenharmony_ci}
3588c2ecf20Sopenharmony_ci
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_cistatic int test_aliases(void)
3618c2ecf20Sopenharmony_ci{
3628c2ecf20Sopenharmony_ci	struct perf_pmu *pmu = NULL;
3638c2ecf20Sopenharmony_ci
3648c2ecf20Sopenharmony_ci	while ((pmu = perf_pmu__scan(pmu)) != NULL) {
3658c2ecf20Sopenharmony_ci		int count = 0;
3668c2ecf20Sopenharmony_ci
3678c2ecf20Sopenharmony_ci		if (list_empty(&pmu->format)) {
3688c2ecf20Sopenharmony_ci			pr_debug2("skipping testing PMU %s\n", pmu->name);
3698c2ecf20Sopenharmony_ci			continue;
3708c2ecf20Sopenharmony_ci		}
3718c2ecf20Sopenharmony_ci
3728c2ecf20Sopenharmony_ci		if (__test__pmu_event_aliases(pmu->name, &count)) {
3738c2ecf20Sopenharmony_ci			pr_debug("testing PMU %s aliases: failed\n", pmu->name);
3748c2ecf20Sopenharmony_ci			return -1;
3758c2ecf20Sopenharmony_ci		}
3768c2ecf20Sopenharmony_ci
3778c2ecf20Sopenharmony_ci		if (count == 0)
3788c2ecf20Sopenharmony_ci			pr_debug3("testing PMU %s aliases: no events to match\n",
3798c2ecf20Sopenharmony_ci				  pmu->name);
3808c2ecf20Sopenharmony_ci		else
3818c2ecf20Sopenharmony_ci			pr_debug("testing PMU %s aliases: pass\n", pmu->name);
3828c2ecf20Sopenharmony_ci	}
3838c2ecf20Sopenharmony_ci
3848c2ecf20Sopenharmony_ci	return 0;
3858c2ecf20Sopenharmony_ci}
3868c2ecf20Sopenharmony_ci
3878c2ecf20Sopenharmony_cistatic bool is_number(const char *str)
3888c2ecf20Sopenharmony_ci{
3898c2ecf20Sopenharmony_ci	char *end_ptr;
3908c2ecf20Sopenharmony_ci	double v;
3918c2ecf20Sopenharmony_ci
3928c2ecf20Sopenharmony_ci	errno = 0;
3938c2ecf20Sopenharmony_ci	v = strtod(str, &end_ptr);
3948c2ecf20Sopenharmony_ci	(void)v; // We're not interested in this value, only if it is valid
3958c2ecf20Sopenharmony_ci	return errno == 0 && end_ptr != str;
3968c2ecf20Sopenharmony_ci}
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_cistatic int check_parse_id(const char *id, struct parse_events_error *error,
3998c2ecf20Sopenharmony_ci			  struct perf_pmu *fake_pmu)
4008c2ecf20Sopenharmony_ci{
4018c2ecf20Sopenharmony_ci	struct evlist *evlist;
4028c2ecf20Sopenharmony_ci	int ret;
4038c2ecf20Sopenharmony_ci
4048c2ecf20Sopenharmony_ci	/* Numbers are always valid. */
4058c2ecf20Sopenharmony_ci	if (is_number(id))
4068c2ecf20Sopenharmony_ci		return 0;
4078c2ecf20Sopenharmony_ci
4088c2ecf20Sopenharmony_ci	evlist = evlist__new();
4098c2ecf20Sopenharmony_ci	if (!evlist)
4108c2ecf20Sopenharmony_ci		return -ENOMEM;
4118c2ecf20Sopenharmony_ci	ret = __parse_events(evlist, id, error, fake_pmu);
4128c2ecf20Sopenharmony_ci	evlist__delete(evlist);
4138c2ecf20Sopenharmony_ci	return ret;
4148c2ecf20Sopenharmony_ci}
4158c2ecf20Sopenharmony_ci
4168c2ecf20Sopenharmony_cistatic int check_parse_cpu(const char *id, bool same_cpu, struct pmu_event *pe)
4178c2ecf20Sopenharmony_ci{
4188c2ecf20Sopenharmony_ci	struct parse_events_error error = { .idx = 0, };
4198c2ecf20Sopenharmony_ci
4208c2ecf20Sopenharmony_ci	int ret = check_parse_id(id, &error, NULL);
4218c2ecf20Sopenharmony_ci	if (ret && same_cpu) {
4228c2ecf20Sopenharmony_ci		pr_warning("Parse event failed metric '%s' id '%s' expr '%s'\n",
4238c2ecf20Sopenharmony_ci			pe->metric_name, id, pe->metric_expr);
4248c2ecf20Sopenharmony_ci		pr_warning("Error string '%s' help '%s'\n", error.str,
4258c2ecf20Sopenharmony_ci			error.help);
4268c2ecf20Sopenharmony_ci	} else if (ret) {
4278c2ecf20Sopenharmony_ci		pr_debug3("Parse event failed, but for an event that may not be supported by this CPU.\nid '%s' metric '%s' expr '%s'\n",
4288c2ecf20Sopenharmony_ci			  id, pe->metric_name, pe->metric_expr);
4298c2ecf20Sopenharmony_ci		ret = 0;
4308c2ecf20Sopenharmony_ci	}
4318c2ecf20Sopenharmony_ci	free(error.str);
4328c2ecf20Sopenharmony_ci	free(error.help);
4338c2ecf20Sopenharmony_ci	free(error.first_str);
4348c2ecf20Sopenharmony_ci	free(error.first_help);
4358c2ecf20Sopenharmony_ci	return ret;
4368c2ecf20Sopenharmony_ci}
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_cistatic int check_parse_fake(const char *id)
4398c2ecf20Sopenharmony_ci{
4408c2ecf20Sopenharmony_ci	struct parse_events_error error = { .idx = 0, };
4418c2ecf20Sopenharmony_ci	int ret = check_parse_id(id, &error, &perf_pmu__fake);
4428c2ecf20Sopenharmony_ci
4438c2ecf20Sopenharmony_ci	free(error.str);
4448c2ecf20Sopenharmony_ci	free(error.help);
4458c2ecf20Sopenharmony_ci	free(error.first_str);
4468c2ecf20Sopenharmony_ci	free(error.first_help);
4478c2ecf20Sopenharmony_ci	return ret;
4488c2ecf20Sopenharmony_ci}
4498c2ecf20Sopenharmony_ci
4508c2ecf20Sopenharmony_cistatic void expr_failure(const char *msg,
4518c2ecf20Sopenharmony_ci			 const struct pmu_events_map *map,
4528c2ecf20Sopenharmony_ci			 const struct pmu_event *pe)
4538c2ecf20Sopenharmony_ci{
4548c2ecf20Sopenharmony_ci	pr_debug("%s for map %s %s %s\n",
4558c2ecf20Sopenharmony_ci		msg, map->cpuid, map->version, map->type);
4568c2ecf20Sopenharmony_ci	pr_debug("On metric %s\n", pe->metric_name);
4578c2ecf20Sopenharmony_ci	pr_debug("On expression %s\n", pe->metric_expr);
4588c2ecf20Sopenharmony_ci}
4598c2ecf20Sopenharmony_ci
4608c2ecf20Sopenharmony_cistatic int test_parsing(void)
4618c2ecf20Sopenharmony_ci{
4628c2ecf20Sopenharmony_ci	struct pmu_events_map *cpus_map = perf_pmu__find_map(NULL);
4638c2ecf20Sopenharmony_ci	struct pmu_events_map *map;
4648c2ecf20Sopenharmony_ci	struct pmu_event *pe;
4658c2ecf20Sopenharmony_ci	int i, j, k;
4668c2ecf20Sopenharmony_ci	int ret = 0;
4678c2ecf20Sopenharmony_ci	struct expr_parse_ctx ctx;
4688c2ecf20Sopenharmony_ci	double result;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	i = 0;
4718c2ecf20Sopenharmony_ci	for (;;) {
4728c2ecf20Sopenharmony_ci		map = &pmu_events_map[i++];
4738c2ecf20Sopenharmony_ci		if (!map->table)
4748c2ecf20Sopenharmony_ci			break;
4758c2ecf20Sopenharmony_ci		j = 0;
4768c2ecf20Sopenharmony_ci		for (;;) {
4778c2ecf20Sopenharmony_ci			struct hashmap_entry *cur;
4788c2ecf20Sopenharmony_ci			size_t bkt;
4798c2ecf20Sopenharmony_ci
4808c2ecf20Sopenharmony_ci			pe = &map->table[j++];
4818c2ecf20Sopenharmony_ci			if (!pe->name && !pe->metric_group && !pe->metric_name)
4828c2ecf20Sopenharmony_ci				break;
4838c2ecf20Sopenharmony_ci			if (!pe->metric_expr)
4848c2ecf20Sopenharmony_ci				continue;
4858c2ecf20Sopenharmony_ci			expr__ctx_init(&ctx);
4868c2ecf20Sopenharmony_ci			if (expr__find_other(pe->metric_expr, NULL, &ctx, 0)
4878c2ecf20Sopenharmony_ci				  < 0) {
4888c2ecf20Sopenharmony_ci				expr_failure("Parse other failed", map, pe);
4898c2ecf20Sopenharmony_ci				ret++;
4908c2ecf20Sopenharmony_ci				continue;
4918c2ecf20Sopenharmony_ci			}
4928c2ecf20Sopenharmony_ci
4938c2ecf20Sopenharmony_ci			/*
4948c2ecf20Sopenharmony_ci			 * Add all ids with a made up value. The value may
4958c2ecf20Sopenharmony_ci			 * trigger divide by zero when subtracted and so try to
4968c2ecf20Sopenharmony_ci			 * make them unique.
4978c2ecf20Sopenharmony_ci			 */
4988c2ecf20Sopenharmony_ci			k = 1;
4998c2ecf20Sopenharmony_ci			hashmap__for_each_entry((&ctx.ids), cur, bkt)
5008c2ecf20Sopenharmony_ci				expr__add_id_val(&ctx, strdup(cur->key), k++);
5018c2ecf20Sopenharmony_ci
5028c2ecf20Sopenharmony_ci			hashmap__for_each_entry((&ctx.ids), cur, bkt) {
5038c2ecf20Sopenharmony_ci				if (check_parse_cpu(cur->key, map == cpus_map,
5048c2ecf20Sopenharmony_ci						   pe))
5058c2ecf20Sopenharmony_ci					ret++;
5068c2ecf20Sopenharmony_ci			}
5078c2ecf20Sopenharmony_ci
5088c2ecf20Sopenharmony_ci			if (expr__parse(&result, &ctx, pe->metric_expr, 0)) {
5098c2ecf20Sopenharmony_ci				expr_failure("Parse failed", map, pe);
5108c2ecf20Sopenharmony_ci				ret++;
5118c2ecf20Sopenharmony_ci			}
5128c2ecf20Sopenharmony_ci			expr__ctx_clear(&ctx);
5138c2ecf20Sopenharmony_ci		}
5148c2ecf20Sopenharmony_ci	}
5158c2ecf20Sopenharmony_ci	/* TODO: fail when not ok */
5168c2ecf20Sopenharmony_ci	return ret == 0 ? TEST_OK : TEST_SKIP;
5178c2ecf20Sopenharmony_ci}
5188c2ecf20Sopenharmony_ci
5198c2ecf20Sopenharmony_cistruct test_metric {
5208c2ecf20Sopenharmony_ci	const char *str;
5218c2ecf20Sopenharmony_ci};
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_cistatic struct test_metric metrics[] = {
5248c2ecf20Sopenharmony_ci	{ "(unc_p_power_state_occupancy.cores_c0 / unc_p_clockticks) * 100." },
5258c2ecf20Sopenharmony_ci	{ "imx8_ddr0@read\\-cycles@ * 4 * 4", },
5268c2ecf20Sopenharmony_ci	{ "imx8_ddr0@axid\\-read\\,axi_mask\\=0xffff\\,axi_id\\=0x0000@ * 4", },
5278c2ecf20Sopenharmony_ci	{ "(cstate_pkg@c2\\-residency@ / msr@tsc@) * 100", },
5288c2ecf20Sopenharmony_ci	{ "(imx8_ddr0@read\\-cycles@ + imx8_ddr0@write\\-cycles@)", },
5298c2ecf20Sopenharmony_ci};
5308c2ecf20Sopenharmony_ci
5318c2ecf20Sopenharmony_cistatic int metric_parse_fake(const char *str)
5328c2ecf20Sopenharmony_ci{
5338c2ecf20Sopenharmony_ci	struct expr_parse_ctx ctx;
5348c2ecf20Sopenharmony_ci	struct hashmap_entry *cur;
5358c2ecf20Sopenharmony_ci	double result;
5368c2ecf20Sopenharmony_ci	int ret = -1;
5378c2ecf20Sopenharmony_ci	size_t bkt;
5388c2ecf20Sopenharmony_ci	int i;
5398c2ecf20Sopenharmony_ci
5408c2ecf20Sopenharmony_ci	pr_debug("parsing '%s'\n", str);
5418c2ecf20Sopenharmony_ci
5428c2ecf20Sopenharmony_ci	expr__ctx_init(&ctx);
5438c2ecf20Sopenharmony_ci	if (expr__find_other(str, NULL, &ctx, 0) < 0) {
5448c2ecf20Sopenharmony_ci		pr_err("expr__find_other failed\n");
5458c2ecf20Sopenharmony_ci		return -1;
5468c2ecf20Sopenharmony_ci	}
5478c2ecf20Sopenharmony_ci
5488c2ecf20Sopenharmony_ci	/*
5498c2ecf20Sopenharmony_ci	 * Add all ids with a made up value. The value may
5508c2ecf20Sopenharmony_ci	 * trigger divide by zero when subtracted and so try to
5518c2ecf20Sopenharmony_ci	 * make them unique.
5528c2ecf20Sopenharmony_ci	 */
5538c2ecf20Sopenharmony_ci	i = 1;
5548c2ecf20Sopenharmony_ci	hashmap__for_each_entry((&ctx.ids), cur, bkt)
5558c2ecf20Sopenharmony_ci		expr__add_id_val(&ctx, strdup(cur->key), i++);
5568c2ecf20Sopenharmony_ci
5578c2ecf20Sopenharmony_ci	hashmap__for_each_entry((&ctx.ids), cur, bkt) {
5588c2ecf20Sopenharmony_ci		if (check_parse_fake(cur->key)) {
5598c2ecf20Sopenharmony_ci			pr_err("check_parse_fake failed\n");
5608c2ecf20Sopenharmony_ci			goto out;
5618c2ecf20Sopenharmony_ci		}
5628c2ecf20Sopenharmony_ci	}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_ci	if (expr__parse(&result, &ctx, str, 0))
5658c2ecf20Sopenharmony_ci		pr_err("expr__parse failed\n");
5668c2ecf20Sopenharmony_ci	else
5678c2ecf20Sopenharmony_ci		ret = 0;
5688c2ecf20Sopenharmony_ci
5698c2ecf20Sopenharmony_ciout:
5708c2ecf20Sopenharmony_ci	expr__ctx_clear(&ctx);
5718c2ecf20Sopenharmony_ci	return ret;
5728c2ecf20Sopenharmony_ci}
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci/*
5758c2ecf20Sopenharmony_ci * Parse all the metrics for current architecture,
5768c2ecf20Sopenharmony_ci * or all defined cpus via the 'fake_pmu'
5778c2ecf20Sopenharmony_ci * in parse_events.
5788c2ecf20Sopenharmony_ci */
5798c2ecf20Sopenharmony_cistatic int test_parsing_fake(void)
5808c2ecf20Sopenharmony_ci{
5818c2ecf20Sopenharmony_ci	struct pmu_events_map *map;
5828c2ecf20Sopenharmony_ci	struct pmu_event *pe;
5838c2ecf20Sopenharmony_ci	unsigned int i, j;
5848c2ecf20Sopenharmony_ci	int err = 0;
5858c2ecf20Sopenharmony_ci
5868c2ecf20Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(metrics); i++) {
5878c2ecf20Sopenharmony_ci		err = metric_parse_fake(metrics[i].str);
5888c2ecf20Sopenharmony_ci		if (err)
5898c2ecf20Sopenharmony_ci			return err;
5908c2ecf20Sopenharmony_ci	}
5918c2ecf20Sopenharmony_ci
5928c2ecf20Sopenharmony_ci	i = 0;
5938c2ecf20Sopenharmony_ci	for (;;) {
5948c2ecf20Sopenharmony_ci		map = &pmu_events_map[i++];
5958c2ecf20Sopenharmony_ci		if (!map->table)
5968c2ecf20Sopenharmony_ci			break;
5978c2ecf20Sopenharmony_ci		j = 0;
5988c2ecf20Sopenharmony_ci		for (;;) {
5998c2ecf20Sopenharmony_ci			pe = &map->table[j++];
6008c2ecf20Sopenharmony_ci			if (!pe->name && !pe->metric_group && !pe->metric_name)
6018c2ecf20Sopenharmony_ci				break;
6028c2ecf20Sopenharmony_ci			if (!pe->metric_expr)
6038c2ecf20Sopenharmony_ci				continue;
6048c2ecf20Sopenharmony_ci			err = metric_parse_fake(pe->metric_expr);
6058c2ecf20Sopenharmony_ci			if (err)
6068c2ecf20Sopenharmony_ci				return err;
6078c2ecf20Sopenharmony_ci		}
6088c2ecf20Sopenharmony_ci	}
6098c2ecf20Sopenharmony_ci
6108c2ecf20Sopenharmony_ci	return 0;
6118c2ecf20Sopenharmony_ci}
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_cistatic const struct {
6148c2ecf20Sopenharmony_ci	int (*func)(void);
6158c2ecf20Sopenharmony_ci	const char *desc;
6168c2ecf20Sopenharmony_ci} pmu_events_testcase_table[] = {
6178c2ecf20Sopenharmony_ci	{
6188c2ecf20Sopenharmony_ci		.func = test_pmu_event_table,
6198c2ecf20Sopenharmony_ci		.desc = "PMU event table sanity",
6208c2ecf20Sopenharmony_ci	},
6218c2ecf20Sopenharmony_ci	{
6228c2ecf20Sopenharmony_ci		.func = test_aliases,
6238c2ecf20Sopenharmony_ci		.desc = "PMU event map aliases",
6248c2ecf20Sopenharmony_ci	},
6258c2ecf20Sopenharmony_ci	{
6268c2ecf20Sopenharmony_ci		.func = test_parsing,
6278c2ecf20Sopenharmony_ci		.desc = "Parsing of PMU event table metrics",
6288c2ecf20Sopenharmony_ci	},
6298c2ecf20Sopenharmony_ci	{
6308c2ecf20Sopenharmony_ci		.func = test_parsing_fake,
6318c2ecf20Sopenharmony_ci		.desc = "Parsing of PMU event table metrics with fake PMUs",
6328c2ecf20Sopenharmony_ci	},
6338c2ecf20Sopenharmony_ci};
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ciconst char *test__pmu_events_subtest_get_desc(int subtest)
6368c2ecf20Sopenharmony_ci{
6378c2ecf20Sopenharmony_ci	if (subtest < 0 ||
6388c2ecf20Sopenharmony_ci	    subtest >= (int)ARRAY_SIZE(pmu_events_testcase_table))
6398c2ecf20Sopenharmony_ci		return NULL;
6408c2ecf20Sopenharmony_ci	return pmu_events_testcase_table[subtest].desc;
6418c2ecf20Sopenharmony_ci}
6428c2ecf20Sopenharmony_ci
6438c2ecf20Sopenharmony_ciconst char *test__pmu_events_subtest_skip_reason(int subtest)
6448c2ecf20Sopenharmony_ci{
6458c2ecf20Sopenharmony_ci	if (subtest < 0 ||
6468c2ecf20Sopenharmony_ci	    subtest >= (int)ARRAY_SIZE(pmu_events_testcase_table))
6478c2ecf20Sopenharmony_ci		return NULL;
6488c2ecf20Sopenharmony_ci	if (pmu_events_testcase_table[subtest].func != test_parsing)
6498c2ecf20Sopenharmony_ci		return NULL;
6508c2ecf20Sopenharmony_ci	return "some metrics failed";
6518c2ecf20Sopenharmony_ci}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ciint test__pmu_events_subtest_get_nr(void)
6548c2ecf20Sopenharmony_ci{
6558c2ecf20Sopenharmony_ci	return (int)ARRAY_SIZE(pmu_events_testcase_table);
6568c2ecf20Sopenharmony_ci}
6578c2ecf20Sopenharmony_ci
6588c2ecf20Sopenharmony_ciint test__pmu_events(struct test *test __maybe_unused, int subtest)
6598c2ecf20Sopenharmony_ci{
6608c2ecf20Sopenharmony_ci	if (subtest < 0 ||
6618c2ecf20Sopenharmony_ci	    subtest >= (int)ARRAY_SIZE(pmu_events_testcase_table))
6628c2ecf20Sopenharmony_ci		return TEST_FAIL;
6638c2ecf20Sopenharmony_ci	return pmu_events_testcase_table[subtest].func();
6648c2ecf20Sopenharmony_ci}
665