1// SPDX-License-Identifier: GPL-2.0
2#include "math.h"
3#include "parse-events.h"
4#include "pmu.h"
5#include "pmus.h"
6#include "tests.h"
7#include <errno.h>
8#include <stdio.h>
9#include <linux/kernel.h>
10#include <linux/zalloc.h>
11#include "debug.h"
12#include "../pmu-events/pmu-events.h"
13#include <perf/evlist.h>
14#include "util/evlist.h"
15#include "util/expr.h"
16#include "util/hashmap.h"
17#include "util/parse-events.h"
18#include "metricgroup.h"
19#include "stat.h"
20
21struct perf_pmu_test_event {
22	/* used for matching against events from generated pmu-events.c */
23	struct pmu_event event;
24
25	/* used for matching against event aliases */
26	/* extra events for aliases */
27	const char *alias_str;
28
29	/*
30	 * Note: For when PublicDescription does not exist in the JSON, we
31	 * will have no long_desc in pmu_event.long_desc, but long_desc may
32	 * be set in the alias.
33	 */
34	const char *alias_long_desc;
35
36	/* PMU which we should match against */
37	const char *matching_pmu;
38};
39
40struct perf_pmu_test_pmu {
41	struct perf_pmu pmu;
42	struct perf_pmu_test_event const *aliases[10];
43};
44
45static const struct perf_pmu_test_event bp_l1_btb_correct = {
46	.event = {
47		.pmu = "default_core",
48		.name = "bp_l1_btb_correct",
49		.event = "event=0x8a",
50		.desc = "L1 BTB Correction",
51		.topic = "branch",
52	},
53	.alias_str = "event=0x8a",
54	.alias_long_desc = "L1 BTB Correction",
55};
56
57static const struct perf_pmu_test_event bp_l2_btb_correct = {
58	.event = {
59		.pmu = "default_core",
60		.name = "bp_l2_btb_correct",
61		.event = "event=0x8b",
62		.desc = "L2 BTB Correction",
63		.topic = "branch",
64	},
65	.alias_str = "event=0x8b",
66	.alias_long_desc = "L2 BTB Correction",
67};
68
69static const struct perf_pmu_test_event segment_reg_loads_any = {
70	.event = {
71		.pmu = "default_core",
72		.name = "segment_reg_loads.any",
73		.event = "event=6,period=200000,umask=0x80",
74		.desc = "Number of segment register loads",
75		.topic = "other",
76	},
77	.alias_str = "event=0x6,period=0x30d40,umask=0x80",
78	.alias_long_desc = "Number of segment register loads",
79};
80
81static const struct perf_pmu_test_event dispatch_blocked_any = {
82	.event = {
83		.pmu = "default_core",
84		.name = "dispatch_blocked.any",
85		.event = "event=9,period=200000,umask=0x20",
86		.desc = "Memory cluster signals to block micro-op dispatch for any reason",
87		.topic = "other",
88	},
89	.alias_str = "event=0x9,period=0x30d40,umask=0x20",
90	.alias_long_desc = "Memory cluster signals to block micro-op dispatch for any reason",
91};
92
93static const struct perf_pmu_test_event eist_trans = {
94	.event = {
95		.pmu = "default_core",
96		.name = "eist_trans",
97		.event = "event=0x3a,period=200000",
98		.desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions",
99		.topic = "other",
100	},
101	.alias_str = "event=0x3a,period=0x30d40",
102	.alias_long_desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions",
103};
104
105static const struct perf_pmu_test_event l3_cache_rd = {
106	.event = {
107		.pmu = "default_core",
108		.name = "l3_cache_rd",
109		.event = "event=0x40",
110		.desc = "L3 cache access, read",
111		.long_desc = "Attributable Level 3 cache access, read",
112		.topic = "cache",
113	},
114	.alias_str = "event=0x40",
115	.alias_long_desc = "Attributable Level 3 cache access, read",
116};
117
118static const struct perf_pmu_test_event *core_events[] = {
119	&bp_l1_btb_correct,
120	&bp_l2_btb_correct,
121	&segment_reg_loads_any,
122	&dispatch_blocked_any,
123	&eist_trans,
124	&l3_cache_rd,
125	NULL
126};
127
128static const struct perf_pmu_test_event uncore_hisi_ddrc_flux_wcmd = {
129	.event = {
130		.name = "uncore_hisi_ddrc.flux_wcmd",
131		.event = "event=2",
132		.desc = "DDRC write commands",
133		.topic = "uncore",
134		.long_desc = "DDRC write commands",
135		.pmu = "hisi_sccl,ddrc",
136	},
137	.alias_str = "event=0x2",
138	.alias_long_desc = "DDRC write commands",
139	.matching_pmu = "hisi_sccl1_ddrc2",
140};
141
142static const struct perf_pmu_test_event unc_cbo_xsnp_response_miss_eviction = {
143	.event = {
144		.name = "unc_cbo_xsnp_response.miss_eviction",
145		.event = "event=0x22,umask=0x81",
146		.desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core",
147		.topic = "uncore",
148		.long_desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core",
149		.pmu = "uncore_cbox",
150	},
151	.alias_str = "event=0x22,umask=0x81",
152	.alias_long_desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core",
153	.matching_pmu = "uncore_cbox_0",
154};
155
156static const struct perf_pmu_test_event uncore_hyphen = {
157	.event = {
158		.name = "event-hyphen",
159		.event = "event=0xe0",
160		.desc = "UNC_CBO_HYPHEN",
161		.topic = "uncore",
162		.long_desc = "UNC_CBO_HYPHEN",
163		.pmu = "uncore_cbox",
164	},
165	.alias_str = "event=0xe0",
166	.alias_long_desc = "UNC_CBO_HYPHEN",
167	.matching_pmu = "uncore_cbox_0",
168};
169
170static const struct perf_pmu_test_event uncore_two_hyph = {
171	.event = {
172		.name = "event-two-hyph",
173		.event = "event=0xc0",
174		.desc = "UNC_CBO_TWO_HYPH",
175		.topic = "uncore",
176		.long_desc = "UNC_CBO_TWO_HYPH",
177		.pmu = "uncore_cbox",
178	},
179	.alias_str = "event=0xc0",
180	.alias_long_desc = "UNC_CBO_TWO_HYPH",
181	.matching_pmu = "uncore_cbox_0",
182};
183
184static const struct perf_pmu_test_event uncore_hisi_l3c_rd_hit_cpipe = {
185	.event = {
186		.name = "uncore_hisi_l3c.rd_hit_cpipe",
187		.event = "event=7",
188		.desc = "Total read hits",
189		.topic = "uncore",
190		.long_desc = "Total read hits",
191		.pmu = "hisi_sccl,l3c",
192	},
193	.alias_str = "event=0x7",
194	.alias_long_desc = "Total read hits",
195	.matching_pmu = "hisi_sccl3_l3c7",
196};
197
198static const struct perf_pmu_test_event uncore_imc_free_running_cache_miss = {
199	.event = {
200		.name = "uncore_imc_free_running.cache_miss",
201		.event = "event=0x12",
202		.desc = "Total cache misses",
203		.topic = "uncore",
204		.long_desc = "Total cache misses",
205		.pmu = "uncore_imc_free_running",
206	},
207	.alias_str = "event=0x12",
208	.alias_long_desc = "Total cache misses",
209	.matching_pmu = "uncore_imc_free_running_0",
210};
211
212static const struct perf_pmu_test_event uncore_imc_cache_hits = {
213	.event = {
214		.name = "uncore_imc.cache_hits",
215		.event = "event=0x34",
216		.desc = "Total cache hits",
217		.topic = "uncore",
218		.long_desc = "Total cache hits",
219		.pmu = "uncore_imc",
220	},
221	.alias_str = "event=0x34",
222	.alias_long_desc = "Total cache hits",
223	.matching_pmu = "uncore_imc_0",
224};
225
226static const struct perf_pmu_test_event *uncore_events[] = {
227	&uncore_hisi_ddrc_flux_wcmd,
228	&unc_cbo_xsnp_response_miss_eviction,
229	&uncore_hyphen,
230	&uncore_two_hyph,
231	&uncore_hisi_l3c_rd_hit_cpipe,
232	&uncore_imc_free_running_cache_miss,
233	&uncore_imc_cache_hits,
234	NULL
235};
236
237static const struct perf_pmu_test_event sys_ddr_pmu_write_cycles = {
238	.event = {
239		.name = "sys_ddr_pmu.write_cycles",
240		.event = "event=0x2b",
241		.desc = "ddr write-cycles event",
242		.topic = "uncore",
243		.pmu = "uncore_sys_ddr_pmu",
244		.compat = "v8",
245	},
246	.alias_str = "event=0x2b",
247	.alias_long_desc = "ddr write-cycles event",
248	.matching_pmu = "uncore_sys_ddr_pmu0",
249};
250
251static const struct perf_pmu_test_event sys_ccn_pmu_read_cycles = {
252	.event = {
253		.name = "sys_ccn_pmu.read_cycles",
254		.event = "config=0x2c",
255		.desc = "ccn read-cycles event",
256		.topic = "uncore",
257		.pmu = "uncore_sys_ccn_pmu",
258		.compat = "0x01",
259	},
260	.alias_str = "config=0x2c",
261	.alias_long_desc = "ccn read-cycles event",
262	.matching_pmu = "uncore_sys_ccn_pmu4",
263};
264
265static const struct perf_pmu_test_event sys_cmn_pmu_hnf_cache_miss = {
266	.event = {
267		.name = "sys_cmn_pmu.hnf_cache_miss",
268		.event = "eventid=1,type=5",
269		.desc = "Counts total cache misses in first lookup result (high priority)",
270		.topic = "uncore",
271		.pmu = "uncore_sys_cmn_pmu",
272		.compat = "(434|436|43c|43a).*",
273	},
274	.alias_str = "eventid=0x1,type=0x5",
275	.alias_long_desc = "Counts total cache misses in first lookup result (high priority)",
276	.matching_pmu = "uncore_sys_cmn_pmu0",
277};
278
279static const struct perf_pmu_test_event *sys_events[] = {
280	&sys_ddr_pmu_write_cycles,
281	&sys_ccn_pmu_read_cycles,
282	&sys_cmn_pmu_hnf_cache_miss,
283	NULL
284};
285
286static bool is_same(const char *reference, const char *test)
287{
288	if (!reference && !test)
289		return true;
290
291	if (reference && !test)
292		return false;
293
294	if (!reference && test)
295		return false;
296
297	return !strcmp(reference, test);
298}
299
300static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event *e2)
301{
302	if (!is_same(e1->name, e2->name)) {
303		pr_debug2("testing event e1 %s: mismatched name string, %s vs %s\n",
304			  e1->name, e1->name, e2->name);
305		return -1;
306	}
307
308	if (!is_same(e1->compat, e2->compat)) {
309		pr_debug2("testing event e1 %s: mismatched compat string, %s vs %s\n",
310			  e1->name, e1->compat, e2->compat);
311		return -1;
312	}
313
314	if (!is_same(e1->event, e2->event)) {
315		pr_debug2("testing event e1 %s: mismatched event, %s vs %s\n",
316			  e1->name, e1->event, e2->event);
317		return -1;
318	}
319
320	if (!is_same(e1->desc, e2->desc)) {
321		pr_debug2("testing event e1 %s: mismatched desc, %s vs %s\n",
322			  e1->name, e1->desc, e2->desc);
323		return -1;
324	}
325
326	if (!is_same(e1->topic, e2->topic)) {
327		pr_debug2("testing event e1 %s: mismatched topic, %s vs %s\n",
328			  e1->name, e1->topic, e2->topic);
329		return -1;
330	}
331
332	if (!is_same(e1->long_desc, e2->long_desc)) {
333		pr_debug2("testing event e1 %s: mismatched long_desc, %s vs %s\n",
334			  e1->name, e1->long_desc, e2->long_desc);
335		return -1;
336	}
337
338	if (!is_same(e1->pmu, e2->pmu)) {
339		pr_debug2("testing event e1 %s: mismatched pmu string, %s vs %s\n",
340			  e1->name, e1->pmu, e2->pmu);
341		return -1;
342	}
343
344	if (!is_same(e1->unit, e2->unit)) {
345		pr_debug2("testing event e1 %s: mismatched unit, %s vs %s\n",
346			  e1->name, e1->unit, e2->unit);
347		return -1;
348	}
349
350	if (e1->perpkg != e2->perpkg) {
351		pr_debug2("testing event e1 %s: mismatched perpkg, %d vs %d\n",
352			  e1->name, e1->perpkg, e2->perpkg);
353		return -1;
354	}
355
356	if (e1->deprecated != e2->deprecated) {
357		pr_debug2("testing event e1 %s: mismatched deprecated, %d vs %d\n",
358			  e1->name, e1->deprecated, e2->deprecated);
359		return -1;
360	}
361
362	return 0;
363}
364
365static int compare_alias_to_test_event(struct pmu_event_info *alias,
366				struct perf_pmu_test_event const *test_event,
367				char const *pmu_name)
368{
369	struct pmu_event const *event = &test_event->event;
370
371	/* An alias was found, ensure everything is in order */
372	if (!is_same(alias->name, event->name)) {
373		pr_debug("testing aliases PMU %s: mismatched name, %s vs %s\n",
374			  pmu_name, alias->name, event->name);
375		return -1;
376	}
377
378	if (!is_same(alias->desc, event->desc)) {
379		pr_debug("testing aliases PMU %s: mismatched desc, %s vs %s\n",
380			  pmu_name, alias->desc, event->desc);
381		return -1;
382	}
383
384	if (!is_same(alias->long_desc, test_event->alias_long_desc)) {
385		pr_debug("testing aliases PMU %s: mismatched long_desc, %s vs %s\n",
386			  pmu_name, alias->long_desc,
387			  test_event->alias_long_desc);
388		return -1;
389	}
390
391	if (!is_same(alias->topic, event->topic)) {
392		pr_debug("testing aliases PMU %s: mismatched topic, %s vs %s\n",
393			  pmu_name, alias->topic, event->topic);
394		return -1;
395	}
396
397	if (!is_same(alias->str, test_event->alias_str)) {
398		pr_debug("testing aliases PMU %s: mismatched str, %s vs %s\n",
399			  pmu_name, alias->str, test_event->alias_str);
400		return -1;
401	}
402
403	if (!is_same(alias->long_desc, test_event->alias_long_desc)) {
404		pr_debug("testing aliases PMU %s: mismatched long desc, %s vs %s\n",
405			  pmu_name, alias->str, test_event->alias_long_desc);
406		return -1;
407	}
408
409	if (!is_same(alias->pmu_name, test_event->event.pmu) &&
410	    !is_same(alias->pmu_name, "default_core")) {
411		pr_debug("testing aliases PMU %s: mismatched pmu_name, %s vs %s\n",
412			  pmu_name, alias->pmu_name, test_event->event.pmu);
413		return -1;
414	}
415
416	return 0;
417}
418
419static int test__pmu_event_table_core_callback(const struct pmu_event *pe,
420					       const struct pmu_events_table *table __maybe_unused,
421					       void *data)
422{
423	int *map_events = data;
424	struct perf_pmu_test_event const **test_event_table;
425	bool found = false;
426
427	if (strcmp(pe->pmu, "default_core"))
428		test_event_table = &uncore_events[0];
429	else
430		test_event_table = &core_events[0];
431
432	for (; *test_event_table; test_event_table++) {
433		struct perf_pmu_test_event const *test_event = *test_event_table;
434		struct pmu_event const *event = &test_event->event;
435
436		if (strcmp(pe->name, event->name))
437			continue;
438		found = true;
439		(*map_events)++;
440
441		if (compare_pmu_events(pe, event))
442			return -1;
443
444		pr_debug("testing event table %s: pass\n", pe->name);
445	}
446	if (!found) {
447		pr_err("testing event table: could not find event %s\n", pe->name);
448		return -1;
449	}
450	return 0;
451}
452
453static int test__pmu_event_table_sys_callback(const struct pmu_event *pe,
454					      const struct pmu_events_table *table __maybe_unused,
455					      void *data)
456{
457	int *map_events = data;
458	struct perf_pmu_test_event const **test_event_table;
459	bool found = false;
460
461	test_event_table = &sys_events[0];
462
463	for (; *test_event_table; test_event_table++) {
464		struct perf_pmu_test_event const *test_event = *test_event_table;
465		struct pmu_event const *event = &test_event->event;
466
467		if (strcmp(pe->name, event->name))
468			continue;
469		found = true;
470		(*map_events)++;
471
472		if (compare_pmu_events(pe, event))
473			return TEST_FAIL;
474
475		pr_debug("testing sys event table %s: pass\n", pe->name);
476	}
477	if (!found) {
478		pr_debug("testing sys event table: could not find event %s\n", pe->name);
479		return TEST_FAIL;
480	}
481	return TEST_OK;
482}
483
484/* Verify generated events from pmu-events.c are as expected */
485static int test__pmu_event_table(struct test_suite *test __maybe_unused,
486				 int subtest __maybe_unused)
487{
488	const struct pmu_events_table *sys_event_table =
489		find_sys_events_table("pmu_events__test_soc_sys");
490	const struct pmu_events_table *table = find_core_events_table("testarch", "testcpu");
491	int map_events = 0, expected_events, err;
492
493	/* ignore 3x sentinels */
494	expected_events = ARRAY_SIZE(core_events) +
495			  ARRAY_SIZE(uncore_events) +
496			  ARRAY_SIZE(sys_events) - 3;
497
498	if (!table || !sys_event_table)
499		return -1;
500
501	err = pmu_events_table__for_each_event(table, /*pmu=*/ NULL,
502					      test__pmu_event_table_core_callback,
503					      &map_events);
504	if (err)
505		return err;
506
507	err = pmu_events_table__for_each_event(sys_event_table, /*pmu=*/ NULL,
508					      test__pmu_event_table_sys_callback,
509					      &map_events);
510	if (err)
511		return err;
512
513	if (map_events != expected_events) {
514		pr_err("testing event table: found %d, but expected %d\n",
515		       map_events, expected_events);
516		return TEST_FAIL;
517	}
518
519	return 0;
520}
521
522struct test_core_pmu_event_aliases_cb_args {
523	struct perf_pmu_test_event const *test_event;
524	int *count;
525};
526
527static int test_core_pmu_event_aliases_cb(void *state, struct pmu_event_info *alias)
528{
529	struct test_core_pmu_event_aliases_cb_args *args = state;
530
531	if (compare_alias_to_test_event(alias, args->test_event, alias->pmu->name))
532		return -1;
533	(*args->count)++;
534	pr_debug2("testing aliases core PMU %s: matched event %s\n",
535		alias->pmu_name, alias->name);
536	return 0;
537}
538
539/* Verify aliases are as expected */
540static int __test_core_pmu_event_aliases(const char *pmu_name, int *count)
541{
542	struct perf_pmu_test_event const **test_event_table;
543	struct perf_pmu *pmu;
544	int res = 0;
545	const struct pmu_events_table *table = find_core_events_table("testarch", "testcpu");
546
547	if (!table)
548		return -1;
549
550	test_event_table = &core_events[0];
551
552	pmu = zalloc(sizeof(*pmu));
553	if (!pmu)
554		return -1;
555
556	INIT_LIST_HEAD(&pmu->format);
557	INIT_LIST_HEAD(&pmu->aliases);
558	INIT_LIST_HEAD(&pmu->caps);
559	INIT_LIST_HEAD(&pmu->list);
560	pmu->name = strdup(pmu_name);
561	pmu->is_core = true;
562
563	pmu->events_table = table;
564	pmu_add_cpu_aliases_table(pmu, table);
565	pmu->cpu_aliases_added = true;
566	pmu->sysfs_aliases_loaded = true;
567
568	res = pmu_events_table__find_event(table, pmu, "bp_l1_btb_correct", NULL, NULL);
569	if (res != 0) {
570		pr_debug("Missing test event in test architecture");
571		return res;
572	}
573	for (; *test_event_table; test_event_table++) {
574		struct perf_pmu_test_event test_event = **test_event_table;
575		struct pmu_event const *event = &test_event.event;
576		struct test_core_pmu_event_aliases_cb_args args = {
577			.test_event = &test_event,
578			.count = count,
579		};
580		int err;
581
582		test_event.event.pmu = pmu_name;
583		err = perf_pmu__find_event(pmu, event->name, &args,
584					   test_core_pmu_event_aliases_cb);
585		if (err)
586			res = err;
587	}
588	perf_pmu__delete(pmu);
589
590	return res;
591}
592
593static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
594{
595	int alias_count = 0, to_match_count = 0, matched_count = 0;
596	struct perf_pmu_test_event const **table;
597	struct perf_pmu *pmu = &test_pmu->pmu;
598	const char *pmu_name = pmu->name;
599	const struct pmu_events_table *events_table;
600	int res = 0;
601
602	events_table = find_core_events_table("testarch", "testcpu");
603	if (!events_table)
604		return -1;
605	pmu->events_table = events_table;
606	pmu_add_cpu_aliases_table(pmu, events_table);
607	pmu->cpu_aliases_added = true;
608	pmu->sysfs_aliases_loaded = true;
609	pmu_add_sys_aliases(pmu);
610
611	/* Count how many aliases we generated */
612	alias_count = perf_pmu__num_events(pmu);
613
614	/* Count how many aliases we expect from the known table */
615	for (table = &test_pmu->aliases[0]; *table; table++)
616		to_match_count++;
617
618	if (alias_count != to_match_count) {
619		pr_debug("testing aliases uncore PMU %s: mismatch expected aliases (%d) vs found (%d)\n",
620			 pmu_name, to_match_count, alias_count);
621		return -1;
622	}
623
624	for (table = &test_pmu->aliases[0]; *table; table++) {
625		struct perf_pmu_test_event test_event = **table;
626		struct pmu_event const *event = &test_event.event;
627		int err;
628		struct test_core_pmu_event_aliases_cb_args args = {
629			.test_event = &test_event,
630			.count = &matched_count,
631		};
632
633		if (strcmp(pmu_name, test_event.matching_pmu)) {
634			pr_debug("testing aliases uncore PMU %s: mismatched matching_pmu, %s vs %s\n",
635					pmu_name, test_event.matching_pmu, pmu_name);
636			return -1;
637		}
638
639		err = perf_pmu__find_event(pmu, event->name, &args,
640					   test_core_pmu_event_aliases_cb);
641		if (err) {
642			res = err;
643			pr_debug("testing aliases uncore PMU %s: could not match alias %s\n",
644				 pmu_name, event->name);
645			return -1;
646		}
647	}
648
649	if (alias_count != matched_count) {
650		pr_debug("testing aliases uncore PMU %s: mismatch found aliases (%d) vs matched (%d)\n",
651			 pmu_name, matched_count, alias_count);
652		res = -1;
653	}
654	return res;
655}
656
657static struct perf_pmu_test_pmu test_pmus[] = {
658	{
659		.pmu = {
660			.name = "hisi_sccl1_ddrc2",
661			.is_uncore = 1,
662		},
663		.aliases = {
664			&uncore_hisi_ddrc_flux_wcmd,
665		},
666	},
667	{
668		.pmu = {
669			.name = "uncore_cbox_0",
670			.is_uncore = 1,
671		},
672		.aliases = {
673			&unc_cbo_xsnp_response_miss_eviction,
674			&uncore_hyphen,
675			&uncore_two_hyph,
676		},
677	},
678	{
679		.pmu = {
680			.name = "hisi_sccl3_l3c7",
681			.is_uncore = 1,
682		},
683		.aliases = {
684			&uncore_hisi_l3c_rd_hit_cpipe,
685		},
686	},
687	{
688		.pmu = {
689			.name = "uncore_imc_free_running_0",
690			.is_uncore = 1,
691		},
692		.aliases = {
693			&uncore_imc_free_running_cache_miss,
694		},
695	},
696	{
697		.pmu = {
698			.name = "uncore_imc_0",
699			.is_uncore = 1,
700		},
701		.aliases = {
702			&uncore_imc_cache_hits,
703		},
704	},
705	{
706		.pmu = {
707			.name = "uncore_sys_ddr_pmu0",
708			.is_uncore = 1,
709			.id = "v8",
710		},
711		.aliases = {
712			&sys_ddr_pmu_write_cycles,
713		},
714	},
715	{
716		.pmu = {
717			.name = "uncore_sys_ccn_pmu4",
718			.is_uncore = 1,
719			.id = "0x01",
720		},
721		.aliases = {
722			&sys_ccn_pmu_read_cycles,
723		},
724	},
725	{
726		.pmu = {
727			.name = (char *)"uncore_sys_cmn_pmu0",
728			.is_uncore = 1,
729			.id = (char *)"43401",
730		},
731		.aliases = {
732			&sys_cmn_pmu_hnf_cache_miss,
733		},
734	},
735	{
736		.pmu = {
737			.name = (char *)"uncore_sys_cmn_pmu0",
738			.is_uncore = 1,
739			.id = (char *)"43602",
740		},
741		.aliases = {
742			&sys_cmn_pmu_hnf_cache_miss,
743		},
744	},
745	{
746		.pmu = {
747			.name = (char *)"uncore_sys_cmn_pmu0",
748			.is_uncore = 1,
749			.id = (char *)"43c03",
750		},
751		.aliases = {
752			&sys_cmn_pmu_hnf_cache_miss,
753		},
754	},
755	{
756		.pmu = {
757			.name = (char *)"uncore_sys_cmn_pmu0",
758			.is_uncore = 1,
759			.id = (char *)"43a01",
760		},
761		.aliases = {
762			&sys_cmn_pmu_hnf_cache_miss,
763		},
764	}
765};
766
767/* Test that aliases generated are as expected */
768static int test__aliases(struct test_suite *test __maybe_unused,
769			int subtest __maybe_unused)
770{
771	struct perf_pmu *pmu = NULL;
772	unsigned long i;
773
774	while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
775		int count = 0;
776
777		if (list_empty(&pmu->format)) {
778			pr_debug2("skipping testing core PMU %s\n", pmu->name);
779			continue;
780		}
781
782		if (__test_core_pmu_event_aliases(pmu->name, &count)) {
783			pr_debug("testing core PMU %s aliases: failed\n", pmu->name);
784			return -1;
785		}
786
787		if (count == 0) {
788			pr_debug("testing core PMU %s aliases: no events to match\n",
789				  pmu->name);
790			return -1;
791		}
792
793		pr_debug("testing core PMU %s aliases: pass\n", pmu->name);
794	}
795
796	for (i = 0; i < ARRAY_SIZE(test_pmus); i++) {
797		int res;
798
799		INIT_LIST_HEAD(&test_pmus[i].pmu.format);
800		INIT_LIST_HEAD(&test_pmus[i].pmu.aliases);
801		INIT_LIST_HEAD(&test_pmus[i].pmu.caps);
802
803		res = __test_uncore_pmu_event_aliases(&test_pmus[i]);
804		if (res)
805			return res;
806	}
807
808	return 0;
809}
810
811static bool is_number(const char *str)
812{
813	char *end_ptr;
814	double v;
815
816	errno = 0;
817	v = strtod(str, &end_ptr);
818	(void)v; // We're not interested in this value, only if it is valid
819	return errno == 0 && end_ptr != str;
820}
821
822static int check_parse_id(const char *id, struct parse_events_error *error,
823			  struct perf_pmu *fake_pmu)
824{
825	struct evlist *evlist;
826	int ret;
827	char *dup, *cur;
828
829	/* Numbers are always valid. */
830	if (is_number(id))
831		return 0;
832
833	evlist = evlist__new();
834	if (!evlist)
835		return -ENOMEM;
836
837	dup = strdup(id);
838	if (!dup)
839		return -ENOMEM;
840
841	for (cur = strchr(dup, '@') ; cur; cur = strchr(++cur, '@'))
842		*cur = '/';
843
844	ret = __parse_events(evlist, dup, /*pmu_filter=*/NULL, error, fake_pmu,
845			     /*warn_if_reordered=*/true);
846	free(dup);
847
848	evlist__delete(evlist);
849	return ret;
850}
851
852static int check_parse_fake(const char *id)
853{
854	struct parse_events_error error;
855	int ret;
856
857	parse_events_error__init(&error);
858	ret = check_parse_id(id, &error, &perf_pmu__fake);
859	parse_events_error__exit(&error);
860	return ret;
861}
862
863struct metric {
864	struct list_head list;
865	struct metric_ref metric_ref;
866};
867
868static int test__parsing_callback(const struct pmu_metric *pm,
869				  const struct pmu_metrics_table *table,
870				  void *data)
871{
872	int *failures = data;
873	int k;
874	struct evlist *evlist;
875	struct perf_cpu_map *cpus;
876	struct evsel *evsel;
877	struct rblist metric_events = {
878		.nr_entries = 0,
879	};
880	int err = 0;
881
882	if (!pm->metric_expr)
883		return 0;
884
885	pr_debug("Found metric '%s'\n", pm->metric_name);
886	(*failures)++;
887
888	/*
889	 * We need to prepare evlist for stat mode running on CPU 0
890	 * because that's where all the stats are going to be created.
891	 */
892	evlist = evlist__new();
893	if (!evlist)
894		return -ENOMEM;
895
896	cpus = perf_cpu_map__new("0");
897	if (!cpus) {
898		evlist__delete(evlist);
899		return -ENOMEM;
900	}
901
902	perf_evlist__set_maps(&evlist->core, cpus, NULL);
903
904	err = metricgroup__parse_groups_test(evlist, table, pm->metric_name, &metric_events);
905	if (err) {
906		if (!strcmp(pm->metric_name, "M1") || !strcmp(pm->metric_name, "M2") ||
907		    !strcmp(pm->metric_name, "M3")) {
908			(*failures)--;
909			pr_debug("Expected broken metric %s skipping\n", pm->metric_name);
910			err = 0;
911		}
912		goto out_err;
913	}
914
915	err = evlist__alloc_stats(/*config=*/NULL, evlist, /*alloc_raw=*/false);
916	if (err)
917		goto out_err;
918	/*
919	 * Add all ids with a made up value. The value may trigger divide by
920	 * zero when subtracted and so try to make them unique.
921	 */
922	k = 1;
923	evlist__alloc_aggr_stats(evlist, 1);
924	evlist__for_each_entry(evlist, evsel) {
925		evsel->stats->aggr->counts.val = k;
926		if (evsel__name_is(evsel, "duration_time"))
927			update_stats(&walltime_nsecs_stats, k);
928		k++;
929	}
930	evlist__for_each_entry(evlist, evsel) {
931		struct metric_event *me = metricgroup__lookup(&metric_events, evsel, false);
932
933		if (me != NULL) {
934			struct metric_expr *mexp;
935
936			list_for_each_entry (mexp, &me->head, nd) {
937				if (strcmp(mexp->metric_name, pm->metric_name))
938					continue;
939				pr_debug("Result %f\n", test_generic_metric(mexp, 0));
940				err = 0;
941				(*failures)--;
942				goto out_err;
943			}
944		}
945	}
946	pr_debug("Didn't find parsed metric %s", pm->metric_name);
947	err = 1;
948out_err:
949	if (err)
950		pr_debug("Broken metric %s\n", pm->metric_name);
951
952	/* ... cleanup. */
953	metricgroup__rblist_exit(&metric_events);
954	evlist__free_stats(evlist);
955	perf_cpu_map__put(cpus);
956	evlist__delete(evlist);
957	return err;
958}
959
960static int test__parsing(struct test_suite *test __maybe_unused,
961			 int subtest __maybe_unused)
962{
963	int failures = 0;
964
965	pmu_for_each_core_metric(test__parsing_callback, &failures);
966	pmu_for_each_sys_metric(test__parsing_callback, &failures);
967
968	return failures == 0 ? TEST_OK : TEST_FAIL;
969}
970
971struct test_metric {
972	const char *str;
973};
974
975static struct test_metric metrics[] = {
976	{ "(unc_p_power_state_occupancy.cores_c0 / unc_p_clockticks) * 100." },
977	{ "imx8_ddr0@read\\-cycles@ * 4 * 4", },
978	{ "imx8_ddr0@axid\\-read\\,axi_mask\\=0xffff\\,axi_id\\=0x0000@ * 4", },
979	{ "(cstate_pkg@c2\\-residency@ / msr@tsc@) * 100", },
980	{ "(imx8_ddr0@read\\-cycles@ + imx8_ddr0@write\\-cycles@)", },
981};
982
983static int metric_parse_fake(const char *metric_name, const char *str)
984{
985	struct expr_parse_ctx *ctx;
986	struct hashmap_entry *cur;
987	double result;
988	int ret = -1;
989	size_t bkt;
990	int i;
991
992	pr_debug("parsing '%s': '%s'\n", metric_name, str);
993
994	ctx = expr__ctx_new();
995	if (!ctx) {
996		pr_debug("expr__ctx_new failed");
997		return TEST_FAIL;
998	}
999	ctx->sctx.is_test = true;
1000	if (expr__find_ids(str, NULL, ctx) < 0) {
1001		pr_err("expr__find_ids failed\n");
1002		return -1;
1003	}
1004
1005	/*
1006	 * Add all ids with a made up value. The value may
1007	 * trigger divide by zero when subtracted and so try to
1008	 * make them unique.
1009	 */
1010	i = 1;
1011	hashmap__for_each_entry(ctx->ids, cur, bkt)
1012		expr__add_id_val(ctx, strdup(cur->pkey), i++);
1013
1014	hashmap__for_each_entry(ctx->ids, cur, bkt) {
1015		if (check_parse_fake(cur->pkey)) {
1016			pr_err("check_parse_fake failed\n");
1017			goto out;
1018		}
1019	}
1020
1021	ret = 0;
1022	if (expr__parse(&result, ctx, str)) {
1023		/*
1024		 * Parsing failed, make numbers go from large to small which can
1025		 * resolve divide by zero issues.
1026		 */
1027		i = 1024;
1028		hashmap__for_each_entry(ctx->ids, cur, bkt)
1029			expr__add_id_val(ctx, strdup(cur->pkey), i--);
1030		if (expr__parse(&result, ctx, str)) {
1031			pr_err("expr__parse failed for %s\n", metric_name);
1032			/* The following have hard to avoid divide by zero. */
1033			if (!strcmp(metric_name, "tma_clears_resteers") ||
1034			    !strcmp(metric_name, "tma_mispredicts_resteers"))
1035				ret = 0;
1036			else
1037				ret = -1;
1038		}
1039	}
1040
1041out:
1042	expr__ctx_free(ctx);
1043	return ret;
1044}
1045
1046static int test__parsing_fake_callback(const struct pmu_metric *pm,
1047				       const struct pmu_metrics_table *table __maybe_unused,
1048				       void *data __maybe_unused)
1049{
1050	return metric_parse_fake(pm->metric_name, pm->metric_expr);
1051}
1052
1053/*
1054 * Parse all the metrics for current architecture,
1055 * or all defined cpus via the 'fake_pmu'
1056 * in parse_events.
1057 */
1058static int test__parsing_fake(struct test_suite *test __maybe_unused,
1059			      int subtest __maybe_unused)
1060{
1061	int err = 0;
1062
1063	for (size_t i = 0; i < ARRAY_SIZE(metrics); i++) {
1064		err = metric_parse_fake("", metrics[i].str);
1065		if (err)
1066			return err;
1067	}
1068
1069	err = pmu_for_each_core_metric(test__parsing_fake_callback, NULL);
1070	if (err)
1071		return err;
1072
1073	return pmu_for_each_sys_metric(test__parsing_fake_callback, NULL);
1074}
1075
1076static int test__parsing_threshold_callback(const struct pmu_metric *pm,
1077					const struct pmu_metrics_table *table __maybe_unused,
1078					void *data __maybe_unused)
1079{
1080	if (!pm->metric_threshold)
1081		return 0;
1082	return metric_parse_fake(pm->metric_name, pm->metric_threshold);
1083}
1084
1085static int test__parsing_threshold(struct test_suite *test __maybe_unused,
1086			      int subtest __maybe_unused)
1087{
1088	int err = 0;
1089
1090	err = pmu_for_each_core_metric(test__parsing_threshold_callback, NULL);
1091	if (err)
1092		return err;
1093
1094	return pmu_for_each_sys_metric(test__parsing_threshold_callback, NULL);
1095}
1096
1097static struct test_case pmu_events_tests[] = {
1098	TEST_CASE("PMU event table sanity", pmu_event_table),
1099	TEST_CASE("PMU event map aliases", aliases),
1100	TEST_CASE_REASON("Parsing of PMU event table metrics", parsing,
1101			 "some metrics failed"),
1102	TEST_CASE("Parsing of PMU event table metrics with fake PMUs", parsing_fake),
1103	TEST_CASE("Parsing of metric thresholds with fake PMUs", parsing_threshold),
1104	{ .name = NULL, }
1105};
1106
1107struct test_suite suite__pmu_events = {
1108	.desc = "PMU events",
1109	.test_cases = pmu_events_tests,
1110};
1111