3dc1ebee4d9f8bf32491fb9905f03f30f72f9e64
[platform/kernel/linux-starfive.git] / tools / perf / tests / pmu-events.c
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
21 struct 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
40 struct perf_pmu_test_pmu {
41         struct perf_pmu pmu;
42         struct perf_pmu_test_event const *aliases[10];
43 };
44
45 static const struct perf_pmu_test_event bp_l1_btb_correct = {
46         .event = {
47                 .pmu = "cpu",
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
57 static const struct perf_pmu_test_event bp_l2_btb_correct = {
58         .event = {
59                 .pmu = "cpu",
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
69 static const struct perf_pmu_test_event segment_reg_loads_any = {
70         .event = {
71                 .pmu = "cpu",
72                 .name = "segment_reg_loads.any",
73                 .event = "event=0x6,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
81 static const struct perf_pmu_test_event dispatch_blocked_any = {
82         .event = {
83                 .pmu = "cpu",
84                 .name = "dispatch_blocked.any",
85                 .event = "event=0x9,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
93 static const struct perf_pmu_test_event eist_trans = {
94         .event = {
95                 .pmu = "cpu",
96                 .name = "eist_trans",
97                 .event = "event=0x3a,period=200000,umask=0x0",
98                 .desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions",
99                 .topic = "other",
100         },
101         .alias_str = "event=0x3a,period=0x30d40,umask=0",
102         .alias_long_desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions",
103 };
104
105 static const struct perf_pmu_test_event l3_cache_rd = {
106         .event = {
107                 .pmu = "cpu",
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
118 static 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
128 static const struct perf_pmu_test_event uncore_hisi_ddrc_flux_wcmd = {
129         .event = {
130                 .name = "uncore_hisi_ddrc.flux_wcmd",
131                 .event = "event=0x2",
132                 .desc = "DDRC write commands. Unit: hisi_sccl,ddrc",
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
142 static 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. Unit: uncore_cbox",
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
156 static const struct perf_pmu_test_event uncore_hyphen = {
157         .event = {
158                 .name = "event-hyphen",
159                 .event = "event=0xe0,umask=0x00",
160                 .desc = "UNC_CBO_HYPHEN. Unit: uncore_cbox",
161                 .topic = "uncore",
162                 .long_desc = "UNC_CBO_HYPHEN",
163                 .pmu = "uncore_cbox",
164         },
165         .alias_str = "event=0xe0,umask=0",
166         .alias_long_desc = "UNC_CBO_HYPHEN",
167         .matching_pmu = "uncore_cbox_0",
168 };
169
170 static const struct perf_pmu_test_event uncore_two_hyph = {
171         .event = {
172                 .name = "event-two-hyph",
173                 .event = "event=0xc0,umask=0x00",
174                 .desc = "UNC_CBO_TWO_HYPH. Unit: uncore_cbox",
175                 .topic = "uncore",
176                 .long_desc = "UNC_CBO_TWO_HYPH",
177                 .pmu = "uncore_cbox",
178         },
179         .alias_str = "event=0xc0,umask=0",
180         .alias_long_desc = "UNC_CBO_TWO_HYPH",
181         .matching_pmu = "uncore_cbox_0",
182 };
183
184 static 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=0x7",
188                 .desc = "Total read hits. Unit: hisi_sccl,l3c",
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
198 static 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. Unit: uncore_imc_free_running",
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
212 static 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. Unit: uncore_imc",
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
226 static 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
237 static 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. Unit: uncore_sys_ddr_pmu",
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. Unit: uncore_sys_ddr_pmu",
248         .matching_pmu = "uncore_sys_ddr_pmu",
249 };
250
251 static 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. Unit: uncore_sys_ccn_pmu",
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. Unit: uncore_sys_ccn_pmu",
262         .matching_pmu = "uncore_sys_ccn_pmu",
263 };
264
265 static const struct perf_pmu_test_event *sys_events[] = {
266         &sys_ddr_pmu_write_cycles,
267         &sys_ccn_pmu_read_cycles,
268         NULL
269 };
270
271 static bool is_same(const char *reference, const char *test)
272 {
273         if (!reference && !test)
274                 return true;
275
276         if (reference && !test)
277                 return false;
278
279         if (!reference && test)
280                 return false;
281
282         return !strcmp(reference, test);
283 }
284
285 static int compare_pmu_events(const struct pmu_event *e1, const struct pmu_event *e2)
286 {
287         if (!is_same(e1->name, e2->name)) {
288                 pr_debug2("testing event e1 %s: mismatched name string, %s vs %s\n",
289                           e1->name, e1->name, e2->name);
290                 return -1;
291         }
292
293         if (!is_same(e1->compat, e2->compat)) {
294                 pr_debug2("testing event e1 %s: mismatched compat string, %s vs %s\n",
295                           e1->name, e1->compat, e2->compat);
296                 return -1;
297         }
298
299         if (!is_same(e1->event, e2->event)) {
300                 pr_debug2("testing event e1 %s: mismatched event, %s vs %s\n",
301                           e1->name, e1->event, e2->event);
302                 return -1;
303         }
304
305         if (!is_same(e1->desc, e2->desc)) {
306                 pr_debug2("testing event e1 %s: mismatched desc, %s vs %s\n",
307                           e1->name, e1->desc, e2->desc);
308                 return -1;
309         }
310
311         if (!is_same(e1->topic, e2->topic)) {
312                 pr_debug2("testing event e1 %s: mismatched topic, %s vs %s\n",
313                           e1->name, e1->topic, e2->topic);
314                 return -1;
315         }
316
317         if (!is_same(e1->long_desc, e2->long_desc)) {
318                 pr_debug2("testing event e1 %s: mismatched long_desc, %s vs %s\n",
319                           e1->name, e1->long_desc, e2->long_desc);
320                 return -1;
321         }
322
323         if (!is_same(e1->pmu, e2->pmu)) {
324                 pr_debug2("testing event e1 %s: mismatched pmu string, %s vs %s\n",
325                           e1->name, e1->pmu, e2->pmu);
326                 return -1;
327         }
328
329         if (!is_same(e1->unit, e2->unit)) {
330                 pr_debug2("testing event e1 %s: mismatched unit, %s vs %s\n",
331                           e1->name, e1->unit, e2->unit);
332                 return -1;
333         }
334
335         if (e1->perpkg != e2->perpkg) {
336                 pr_debug2("testing event e1 %s: mismatched perpkg, %d vs %d\n",
337                           e1->name, e1->perpkg, e2->perpkg);
338                 return -1;
339         }
340
341         if (e1->deprecated != e2->deprecated) {
342                 pr_debug2("testing event e1 %s: mismatched deprecated, %d vs %d\n",
343                           e1->name, e1->deprecated, e2->deprecated);
344                 return -1;
345         }
346
347         return 0;
348 }
349
350 static int compare_alias_to_test_event(struct pmu_event_info *alias,
351                                 struct perf_pmu_test_event const *test_event,
352                                 char const *pmu_name)
353 {
354         struct pmu_event const *event = &test_event->event;
355
356         /* An alias was found, ensure everything is in order */
357         if (!is_same(alias->name, event->name)) {
358                 pr_debug("testing aliases PMU %s: mismatched name, %s vs %s\n",
359                           pmu_name, alias->name, event->name);
360                 return -1;
361         }
362
363         if (!is_same(alias->desc, event->desc)) {
364                 pr_debug("testing aliases PMU %s: mismatched desc, %s vs %s\n",
365                           pmu_name, alias->desc, event->desc);
366                 return -1;
367         }
368
369         if (!is_same(alias->long_desc, test_event->alias_long_desc)) {
370                 pr_debug("testing aliases PMU %s: mismatched long_desc, %s vs %s\n",
371                           pmu_name, alias->long_desc,
372                           test_event->alias_long_desc);
373                 return -1;
374         }
375
376         if (!is_same(alias->topic, event->topic)) {
377                 pr_debug("testing aliases PMU %s: mismatched topic, %s vs %s\n",
378                           pmu_name, alias->topic, event->topic);
379                 return -1;
380         }
381
382         if (!is_same(alias->str, test_event->alias_str)) {
383                 pr_debug("testing aliases PMU %s: mismatched str, %s vs %s\n",
384                           pmu_name, alias->str, test_event->alias_str);
385                 return -1;
386         }
387
388         if (!is_same(alias->long_desc, test_event->alias_long_desc)) {
389                 pr_debug("testing aliases PMU %s: mismatched long desc, %s vs %s\n",
390                           pmu_name, alias->str, test_event->alias_long_desc);
391                 return -1;
392         }
393
394
395         if (!is_same(alias->pmu_name, test_event->event.pmu)) {
396                 pr_debug("testing aliases PMU %s: mismatched pmu_name, %s vs %s\n",
397                           pmu_name, alias->pmu_name, test_event->event.pmu);
398                 return -1;
399         }
400
401         return 0;
402 }
403
404 static int test__pmu_event_table_core_callback(const struct pmu_event *pe,
405                                                const struct pmu_events_table *table __maybe_unused,
406                                                void *data)
407 {
408         int *map_events = data;
409         struct perf_pmu_test_event const **test_event_table;
410         bool found = false;
411
412         if (strcmp(pe->pmu, "cpu"))
413                 test_event_table = &uncore_events[0];
414         else
415                 test_event_table = &core_events[0];
416
417         for (; *test_event_table; test_event_table++) {
418                 struct perf_pmu_test_event const *test_event = *test_event_table;
419                 struct pmu_event const *event = &test_event->event;
420
421                 if (strcmp(pe->name, event->name))
422                         continue;
423                 found = true;
424                 (*map_events)++;
425
426                 if (compare_pmu_events(pe, event))
427                         return -1;
428
429                 pr_debug("testing event table %s: pass\n", pe->name);
430         }
431         if (!found) {
432                 pr_err("testing event table: could not find event %s\n", pe->name);
433                 return -1;
434         }
435         return 0;
436 }
437
438 static int test__pmu_event_table_sys_callback(const struct pmu_event *pe,
439                                               const struct pmu_events_table *table __maybe_unused,
440                                               void *data)
441 {
442         int *map_events = data;
443         struct perf_pmu_test_event const **test_event_table;
444         bool found = false;
445
446         test_event_table = &sys_events[0];
447
448         for (; *test_event_table; test_event_table++) {
449                 struct perf_pmu_test_event const *test_event = *test_event_table;
450                 struct pmu_event const *event = &test_event->event;
451
452                 if (strcmp(pe->name, event->name))
453                         continue;
454                 found = true;
455                 (*map_events)++;
456
457                 if (compare_pmu_events(pe, event))
458                         return TEST_FAIL;
459
460                 pr_debug("testing sys event table %s: pass\n", pe->name);
461         }
462         if (!found) {
463                 pr_debug("testing sys event table: could not find event %s\n", pe->name);
464                 return TEST_FAIL;
465         }
466         return TEST_OK;
467 }
468
469 /* Verify generated events from pmu-events.c are as expected */
470 static int test__pmu_event_table(struct test_suite *test __maybe_unused,
471                                  int subtest __maybe_unused)
472 {
473         const struct pmu_events_table *sys_event_table =
474                 find_sys_events_table("pmu_events__test_soc_sys");
475         const struct pmu_events_table *table = find_core_events_table("testarch", "testcpu");
476         int map_events = 0, expected_events, err;
477
478         /* ignore 3x sentinels */
479         expected_events = ARRAY_SIZE(core_events) +
480                           ARRAY_SIZE(uncore_events) +
481                           ARRAY_SIZE(sys_events) - 3;
482
483         if (!table || !sys_event_table)
484                 return -1;
485
486         err = pmu_events_table__for_each_event(table, /*pmu=*/ NULL,
487                                               test__pmu_event_table_core_callback,
488                                               &map_events);
489         if (err)
490                 return err;
491
492         err = pmu_events_table__for_each_event(sys_event_table, /*pmu=*/ NULL,
493                                               test__pmu_event_table_sys_callback,
494                                               &map_events);
495         if (err)
496                 return err;
497
498         if (map_events != expected_events) {
499                 pr_err("testing event table: found %d, but expected %d\n",
500                        map_events, expected_events);
501                 return TEST_FAIL;
502         }
503
504         return 0;
505 }
506
507 struct test_core_pmu_event_aliases_cb_args {
508         struct perf_pmu_test_event const *test_event;
509         int *count;
510 };
511
512 static int test_core_pmu_event_aliases_cb(void *state, struct pmu_event_info *alias)
513 {
514         struct test_core_pmu_event_aliases_cb_args *args = state;
515
516         if (compare_alias_to_test_event(alias, args->test_event, alias->pmu->name))
517                 return -1;
518         (*args->count)++;
519         pr_debug2("testing aliases core PMU %s: matched event %s\n",
520                 alias->pmu_name, alias->name);
521         return 0;
522 }
523
524 /* Verify aliases are as expected */
525 static int __test_core_pmu_event_aliases(char *pmu_name, int *count)
526 {
527         struct perf_pmu_test_event const **test_event_table;
528         struct perf_pmu *pmu;
529         int res = 0;
530         const struct pmu_events_table *table = find_core_events_table("testarch", "testcpu");
531
532         if (!table)
533                 return -1;
534
535         test_event_table = &core_events[0];
536
537         pmu = zalloc(sizeof(*pmu));
538         if (!pmu)
539                 return -1;
540
541         INIT_LIST_HEAD(&pmu->format);
542         INIT_LIST_HEAD(&pmu->aliases);
543         INIT_LIST_HEAD(&pmu->caps);
544         INIT_LIST_HEAD(&pmu->list);
545         pmu->name = strdup(pmu_name);
546
547         pmu->events_table = table;
548         pmu_add_cpu_aliases_table(pmu, table);
549         pmu->cpu_aliases_added = true;
550         pmu->sysfs_aliases_loaded = true;
551
552         res = pmu_events_table__find_event(table, pmu, "bp_l1_btb_correct", NULL, NULL);
553         if (res != 0) {
554                 pr_debug("Missing test event in test architecture");
555                 return res;
556         }
557         for (; *test_event_table; test_event_table++) {
558                 struct perf_pmu_test_event test_event = **test_event_table;
559                 struct pmu_event const *event = &test_event.event;
560                 struct test_core_pmu_event_aliases_cb_args args = {
561                         .test_event = &test_event,
562                         .count = count,
563                 };
564                 int err;
565
566                 test_event.event.pmu = pmu_name;
567                 err = perf_pmu__find_event(pmu, event->name, &args,
568                                            test_core_pmu_event_aliases_cb);
569                 if (err)
570                         res = err;
571         }
572         perf_pmu__delete(pmu);
573
574         return res;
575 }
576
577 static int __test_uncore_pmu_event_aliases(struct perf_pmu_test_pmu *test_pmu)
578 {
579         int alias_count = 0, to_match_count = 0, matched_count = 0;
580         struct perf_pmu_test_event const **table;
581         struct perf_pmu *pmu = &test_pmu->pmu;
582         const char *pmu_name = pmu->name;
583         const struct pmu_events_table *events_table;
584         int res = 0;
585
586         events_table = find_core_events_table("testarch", "testcpu");
587         if (!events_table)
588                 return -1;
589         pmu->events_table = events_table;
590         pmu_add_cpu_aliases_table(pmu, events_table);
591         pmu->cpu_aliases_added = true;
592         pmu->sysfs_aliases_loaded = true;
593         pmu_add_sys_aliases(pmu);
594
595         /* Count how many aliases we generated */
596         alias_count = perf_pmu__num_events(pmu);
597
598         /* Count how many aliases we expect from the known table */
599         for (table = &test_pmu->aliases[0]; *table; table++)
600                 to_match_count++;
601
602         if (alias_count != to_match_count) {
603                 pr_debug("testing aliases uncore PMU %s: mismatch expected aliases (%d) vs found (%d)\n",
604                          pmu_name, to_match_count, alias_count);
605                 return -1;
606         }
607
608         for (table = &test_pmu->aliases[0]; *table; table++) {
609                 struct perf_pmu_test_event test_event = **table;
610                 struct pmu_event const *event = &test_event.event;
611                 int err;
612                 struct test_core_pmu_event_aliases_cb_args args = {
613                         .test_event = &test_event,
614                         .count = &matched_count,
615                 };
616
617                 err = perf_pmu__find_event(pmu, event->name, &args,
618                                            test_core_pmu_event_aliases_cb);
619                 if (err) {
620                         res = err;
621                         pr_debug("testing aliases uncore PMU %s: could not match alias %s\n",
622                                  pmu_name, event->name);
623                         return -1;
624                 }
625         }
626
627         if (alias_count != matched_count) {
628                 pr_debug("testing aliases uncore PMU %s: mismatch found aliases (%d) vs matched (%d)\n",
629                          pmu_name, matched_count, alias_count);
630                 res = -1;
631         }
632         return res;
633 }
634
635 static struct perf_pmu_test_pmu test_pmus[] = {
636         {
637                 .pmu = {
638                         .name = (char *)"hisi_sccl1_ddrc2",
639                         .is_uncore = 1,
640                 },
641                 .aliases = {
642                         &uncore_hisi_ddrc_flux_wcmd,
643                 },
644         },
645         {
646                 .pmu = {
647                         .name = (char *)"uncore_cbox_0",
648                         .is_uncore = 1,
649                 },
650                 .aliases = {
651                         &unc_cbo_xsnp_response_miss_eviction,
652                         &uncore_hyphen,
653                         &uncore_two_hyph,
654                 },
655         },
656         {
657                 .pmu = {
658                         .name = (char *)"hisi_sccl3_l3c7",
659                         .is_uncore = 1,
660                 },
661                 .aliases = {
662                         &uncore_hisi_l3c_rd_hit_cpipe,
663                 },
664         },
665         {
666                 .pmu = {
667                         .name = (char *)"uncore_imc_free_running_0",
668                         .is_uncore = 1,
669                 },
670                 .aliases = {
671                         &uncore_imc_free_running_cache_miss,
672                 },
673         },
674         {
675                 .pmu = {
676                         .name = (char *)"uncore_imc_0",
677                         .is_uncore = 1,
678                 },
679                 .aliases = {
680                         &uncore_imc_cache_hits,
681                 },
682         },
683         {
684                 .pmu = {
685                         .name = (char *)"uncore_sys_ddr_pmu0",
686                         .is_uncore = 1,
687                         .id = (char *)"v8",
688                 },
689                 .aliases = {
690                         &sys_ddr_pmu_write_cycles,
691                 },
692         },
693         {
694                 .pmu = {
695                         .name = (char *)"uncore_sys_ccn_pmu4",
696                         .is_uncore = 1,
697                         .id = (char *)"0x01",
698                 },
699                 .aliases = {
700                         &sys_ccn_pmu_read_cycles,
701                 },
702         },
703 };
704
705 /* Test that aliases generated are as expected */
706 static int test__aliases(struct test_suite *test __maybe_unused,
707                         int subtest __maybe_unused)
708 {
709         struct perf_pmu *pmu = NULL;
710         unsigned long i;
711
712         while ((pmu = perf_pmus__scan_core(pmu)) != NULL) {
713                 int count = 0;
714
715                 if (list_empty(&pmu->format)) {
716                         pr_debug2("skipping testing core PMU %s\n", pmu->name);
717                         continue;
718                 }
719
720                 if (__test_core_pmu_event_aliases(pmu->name, &count)) {
721                         pr_debug("testing core PMU %s aliases: failed\n", pmu->name);
722                         return -1;
723                 }
724
725                 if (count == 0) {
726                         pr_debug("testing core PMU %s aliases: no events to match\n",
727                                   pmu->name);
728                         return -1;
729                 }
730
731                 pr_debug("testing core PMU %s aliases: pass\n", pmu->name);
732         }
733
734         for (i = 0; i < ARRAY_SIZE(test_pmus); i++) {
735                 int res;
736
737                 INIT_LIST_HEAD(&test_pmus[i].pmu.format);
738                 INIT_LIST_HEAD(&test_pmus[i].pmu.aliases);
739                 INIT_LIST_HEAD(&test_pmus[i].pmu.caps);
740
741                 res = __test_uncore_pmu_event_aliases(&test_pmus[i]);
742                 if (res)
743                         return res;
744         }
745
746         return 0;
747 }
748
749 static bool is_number(const char *str)
750 {
751         char *end_ptr;
752         double v;
753
754         errno = 0;
755         v = strtod(str, &end_ptr);
756         (void)v; // We're not interested in this value, only if it is valid
757         return errno == 0 && end_ptr != str;
758 }
759
760 static int check_parse_id(const char *id, struct parse_events_error *error,
761                           struct perf_pmu *fake_pmu)
762 {
763         struct evlist *evlist;
764         int ret;
765         char *dup, *cur;
766
767         /* Numbers are always valid. */
768         if (is_number(id))
769                 return 0;
770
771         evlist = evlist__new();
772         if (!evlist)
773                 return -ENOMEM;
774
775         dup = strdup(id);
776         if (!dup)
777                 return -ENOMEM;
778
779         for (cur = strchr(dup, '@') ; cur; cur = strchr(++cur, '@'))
780                 *cur = '/';
781
782         ret = __parse_events(evlist, dup, /*pmu_filter=*/NULL, error, fake_pmu,
783                              /*warn_if_reordered=*/true);
784         free(dup);
785
786         evlist__delete(evlist);
787         return ret;
788 }
789
790 static int check_parse_fake(const char *id)
791 {
792         struct parse_events_error error;
793         int ret;
794
795         parse_events_error__init(&error);
796         ret = check_parse_id(id, &error, &perf_pmu__fake);
797         parse_events_error__exit(&error);
798         return ret;
799 }
800
801 struct metric {
802         struct list_head list;
803         struct metric_ref metric_ref;
804 };
805
806 static int test__parsing_callback(const struct pmu_metric *pm,
807                                   const struct pmu_metrics_table *table,
808                                   void *data)
809 {
810         int *failures = data;
811         int k;
812         struct evlist *evlist;
813         struct perf_cpu_map *cpus;
814         struct evsel *evsel;
815         struct rblist metric_events = {
816                 .nr_entries = 0,
817         };
818         int err = 0;
819
820         if (!pm->metric_expr)
821                 return 0;
822
823         pr_debug("Found metric '%s'\n", pm->metric_name);
824         (*failures)++;
825
826         /*
827          * We need to prepare evlist for stat mode running on CPU 0
828          * because that's where all the stats are going to be created.
829          */
830         evlist = evlist__new();
831         if (!evlist)
832                 return -ENOMEM;
833
834         cpus = perf_cpu_map__new("0");
835         if (!cpus) {
836                 evlist__delete(evlist);
837                 return -ENOMEM;
838         }
839
840         perf_evlist__set_maps(&evlist->core, cpus, NULL);
841
842         err = metricgroup__parse_groups_test(evlist, table, pm->metric_name, &metric_events);
843         if (err) {
844                 if (!strcmp(pm->metric_name, "M1") || !strcmp(pm->metric_name, "M2") ||
845                     !strcmp(pm->metric_name, "M3")) {
846                         (*failures)--;
847                         pr_debug("Expected broken metric %s skipping\n", pm->metric_name);
848                         err = 0;
849                 }
850                 goto out_err;
851         }
852
853         err = evlist__alloc_stats(/*config=*/NULL, evlist, /*alloc_raw=*/false);
854         if (err)
855                 goto out_err;
856         /*
857          * Add all ids with a made up value. The value may trigger divide by
858          * zero when subtracted and so try to make them unique.
859          */
860         k = 1;
861         evlist__alloc_aggr_stats(evlist, 1);
862         evlist__for_each_entry(evlist, evsel) {
863                 evsel->stats->aggr->counts.val = k;
864                 if (evsel__name_is(evsel, "duration_time"))
865                         update_stats(&walltime_nsecs_stats, k);
866                 k++;
867         }
868         evlist__for_each_entry(evlist, evsel) {
869                 struct metric_event *me = metricgroup__lookup(&metric_events, evsel, false);
870
871                 if (me != NULL) {
872                         struct metric_expr *mexp;
873
874                         list_for_each_entry (mexp, &me->head, nd) {
875                                 if (strcmp(mexp->metric_name, pm->metric_name))
876                                         continue;
877                                 pr_debug("Result %f\n", test_generic_metric(mexp, 0));
878                                 err = 0;
879                                 (*failures)--;
880                                 goto out_err;
881                         }
882                 }
883         }
884         pr_debug("Didn't find parsed metric %s", pm->metric_name);
885         err = 1;
886 out_err:
887         if (err)
888                 pr_debug("Broken metric %s\n", pm->metric_name);
889
890         /* ... cleanup. */
891         metricgroup__rblist_exit(&metric_events);
892         evlist__free_stats(evlist);
893         perf_cpu_map__put(cpus);
894         evlist__delete(evlist);
895         return err;
896 }
897
898 static int test__parsing(struct test_suite *test __maybe_unused,
899                          int subtest __maybe_unused)
900 {
901         int failures = 0;
902
903         pmu_for_each_core_metric(test__parsing_callback, &failures);
904         pmu_for_each_sys_metric(test__parsing_callback, &failures);
905
906         return failures == 0 ? TEST_OK : TEST_FAIL;
907 }
908
909 struct test_metric {
910         const char *str;
911 };
912
913 static struct test_metric metrics[] = {
914         { "(unc_p_power_state_occupancy.cores_c0 / unc_p_clockticks) * 100." },
915         { "imx8_ddr0@read\\-cycles@ * 4 * 4", },
916         { "imx8_ddr0@axid\\-read\\,axi_mask\\=0xffff\\,axi_id\\=0x0000@ * 4", },
917         { "(cstate_pkg@c2\\-residency@ / msr@tsc@) * 100", },
918         { "(imx8_ddr0@read\\-cycles@ + imx8_ddr0@write\\-cycles@)", },
919 };
920
921 static int metric_parse_fake(const char *metric_name, const char *str)
922 {
923         struct expr_parse_ctx *ctx;
924         struct hashmap_entry *cur;
925         double result;
926         int ret = -1;
927         size_t bkt;
928         int i;
929
930         pr_debug("parsing '%s': '%s'\n", metric_name, str);
931
932         ctx = expr__ctx_new();
933         if (!ctx) {
934                 pr_debug("expr__ctx_new failed");
935                 return TEST_FAIL;
936         }
937         ctx->sctx.is_test = true;
938         if (expr__find_ids(str, NULL, ctx) < 0) {
939                 pr_err("expr__find_ids failed\n");
940                 return -1;
941         }
942
943         /*
944          * Add all ids with a made up value. The value may
945          * trigger divide by zero when subtracted and so try to
946          * make them unique.
947          */
948         i = 1;
949         hashmap__for_each_entry(ctx->ids, cur, bkt)
950                 expr__add_id_val(ctx, strdup(cur->pkey), i++);
951
952         hashmap__for_each_entry(ctx->ids, cur, bkt) {
953                 if (check_parse_fake(cur->pkey)) {
954                         pr_err("check_parse_fake failed\n");
955                         goto out;
956                 }
957         }
958
959         ret = 0;
960         if (expr__parse(&result, ctx, str)) {
961                 /*
962                  * Parsing failed, make numbers go from large to small which can
963                  * resolve divide by zero issues.
964                  */
965                 i = 1024;
966                 hashmap__for_each_entry(ctx->ids, cur, bkt)
967                         expr__add_id_val(ctx, strdup(cur->pkey), i--);
968                 if (expr__parse(&result, ctx, str)) {
969                         pr_err("expr__parse failed for %s\n", metric_name);
970                         /* The following have hard to avoid divide by zero. */
971                         if (!strcmp(metric_name, "tma_clears_resteers") ||
972                             !strcmp(metric_name, "tma_mispredicts_resteers"))
973                                 ret = 0;
974                         else
975                                 ret = -1;
976                 }
977         }
978
979 out:
980         expr__ctx_free(ctx);
981         return ret;
982 }
983
984 static int test__parsing_fake_callback(const struct pmu_metric *pm,
985                                        const struct pmu_metrics_table *table __maybe_unused,
986                                        void *data __maybe_unused)
987 {
988         return metric_parse_fake(pm->metric_name, pm->metric_expr);
989 }
990
991 /*
992  * Parse all the metrics for current architecture,
993  * or all defined cpus via the 'fake_pmu'
994  * in parse_events.
995  */
996 static int test__parsing_fake(struct test_suite *test __maybe_unused,
997                               int subtest __maybe_unused)
998 {
999         int err = 0;
1000
1001         for (size_t i = 0; i < ARRAY_SIZE(metrics); i++) {
1002                 err = metric_parse_fake("", metrics[i].str);
1003                 if (err)
1004                         return err;
1005         }
1006
1007         err = pmu_for_each_core_metric(test__parsing_fake_callback, NULL);
1008         if (err)
1009                 return err;
1010
1011         return pmu_for_each_sys_metric(test__parsing_fake_callback, NULL);
1012 }
1013
1014 static int test__parsing_threshold_callback(const struct pmu_metric *pm,
1015                                         const struct pmu_metrics_table *table __maybe_unused,
1016                                         void *data __maybe_unused)
1017 {
1018         if (!pm->metric_threshold)
1019                 return 0;
1020         return metric_parse_fake(pm->metric_name, pm->metric_threshold);
1021 }
1022
1023 static int test__parsing_threshold(struct test_suite *test __maybe_unused,
1024                               int subtest __maybe_unused)
1025 {
1026         int err = 0;
1027
1028         err = pmu_for_each_core_metric(test__parsing_threshold_callback, NULL);
1029         if (err)
1030                 return err;
1031
1032         return pmu_for_each_sys_metric(test__parsing_threshold_callback, NULL);
1033 }
1034
1035 static struct test_case pmu_events_tests[] = {
1036         TEST_CASE("PMU event table sanity", pmu_event_table),
1037         TEST_CASE("PMU event map aliases", aliases),
1038         TEST_CASE_REASON("Parsing of PMU event table metrics", parsing,
1039                          "some metrics failed"),
1040         TEST_CASE("Parsing of PMU event table metrics with fake PMUs", parsing_fake),
1041         TEST_CASE("Parsing of metric thresholds with fake PMUs", parsing_threshold),
1042         { .name = NULL, }
1043 };
1044
1045 struct test_suite suite__pmu_events = {
1046         .desc = "PMU events",
1047         .test_cases = pmu_events_tests,
1048 };