1 // SPDX-License-Identifier: GPL-2.0 2 #include "parse-events.h" 3 #include "pmu.h" 4 #include "tests.h" 5 #include <errno.h> 6 #include <stdio.h> 7 #include <linux/kernel.h> 8 #include <linux/zalloc.h> 9 #include "debug.h" 10 #include "../pmu-events/pmu-events.h" 11 12 struct perf_pmu_test_event { 13 struct pmu_event event; 14 15 /* extra events for aliases */ 16 const char *alias_str; 17 18 /* 19 * Note: For when PublicDescription does not exist in the JSON, we 20 * will have no long_desc in pmu_event.long_desc, but long_desc may 21 * be set in the alias. 22 */ 23 const char *alias_long_desc; 24 }; 25 26 static struct perf_pmu_test_event test_cpu_events[] = { 27 { 28 .event = { 29 .name = "bp_l1_btb_correct", 30 .event = "event=0x8a", 31 .desc = "L1 BTB Correction", 32 .topic = "branch", 33 }, 34 .alias_str = "event=0x8a", 35 .alias_long_desc = "L1 BTB Correction", 36 }, 37 { 38 .event = { 39 .name = "bp_l2_btb_correct", 40 .event = "event=0x8b", 41 .desc = "L2 BTB Correction", 42 .topic = "branch", 43 }, 44 .alias_str = "event=0x8b", 45 .alias_long_desc = "L2 BTB Correction", 46 }, 47 { 48 .event = { 49 .name = "segment_reg_loads.any", 50 .event = "umask=0x80,period=200000,event=0x6", 51 .desc = "Number of segment register loads", 52 .topic = "other", 53 }, 54 .alias_str = "umask=0x80,(null)=0x30d40,event=0x6", 55 .alias_long_desc = "Number of segment register loads", 56 }, 57 { 58 .event = { 59 .name = "dispatch_blocked.any", 60 .event = "umask=0x20,period=200000,event=0x9", 61 .desc = "Memory cluster signals to block micro-op dispatch for any reason", 62 .topic = "other", 63 }, 64 .alias_str = "umask=0x20,(null)=0x30d40,event=0x9", 65 .alias_long_desc = "Memory cluster signals to block micro-op dispatch for any reason", 66 }, 67 { 68 .event = { 69 .name = "eist_trans", 70 .event = "umask=0x0,period=200000,event=0x3a", 71 .desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", 72 .topic = "other", 73 }, 74 .alias_str = "umask=0,(null)=0x30d40,event=0x3a", 75 .alias_long_desc = "Number of Enhanced Intel SpeedStep(R) Technology (EIST) transitions", 76 }, 77 { /* sentinel */ 78 .event = { 79 .name = NULL, 80 }, 81 }, 82 }; 83 84 static struct perf_pmu_test_event test_uncore_events[] = { 85 { 86 .event = { 87 .name = "uncore_hisi_ddrc.flux_wcmd", 88 .event = "event=0x2", 89 .desc = "DDRC write commands. Unit: hisi_sccl,ddrc ", 90 .topic = "uncore", 91 .long_desc = "DDRC write commands", 92 .pmu = "hisi_sccl,ddrc", 93 }, 94 .alias_str = "event=0x2", 95 .alias_long_desc = "DDRC write commands", 96 }, 97 { 98 .event = { 99 .name = "unc_cbo_xsnp_response.miss_eviction", 100 .event = "umask=0x81,event=0x22", 101 .desc = "Unit: uncore_cbox A cross-core snoop resulted from L3 Eviction which misses in some processor core", 102 .topic = "uncore", 103 .long_desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core", 104 .pmu = "uncore_cbox", 105 }, 106 .alias_str = "umask=0x81,event=0x22", 107 .alias_long_desc = "A cross-core snoop resulted from L3 Eviction which misses in some processor core", 108 }, 109 { /* sentinel */ 110 .event = { 111 .name = NULL, 112 }, 113 } 114 }; 115 116 const int total_test_events_size = ARRAY_SIZE(test_uncore_events); 117 118 static bool is_same(const char *reference, const char *test) 119 { 120 if (!reference && !test) 121 return true; 122 123 if (reference && !test) 124 return false; 125 126 if (!reference && test) 127 return false; 128 129 return !strcmp(reference, test); 130 } 131 132 static struct pmu_events_map *__test_pmu_get_events_map(void) 133 { 134 struct pmu_events_map *map; 135 136 for (map = &pmu_events_map[0]; map->cpuid; map++) { 137 if (!strcmp(map->cpuid, "testcpu")) 138 return map; 139 } 140 141 pr_err("could not find test events map\n"); 142 143 return NULL; 144 } 145 146 /* Verify generated events from pmu-events.c is as expected */ 147 static int __test_pmu_event_table(void) 148 { 149 struct pmu_events_map *map = __test_pmu_get_events_map(); 150 struct pmu_event *table; 151 int map_events = 0, expected_events; 152 153 /* ignore 2x sentinels */ 154 expected_events = ARRAY_SIZE(test_cpu_events) + 155 ARRAY_SIZE(test_uncore_events) - 2; 156 157 if (!map) 158 return -1; 159 160 for (table = map->table; table->name; table++) { 161 struct perf_pmu_test_event *test; 162 struct pmu_event *te; 163 bool found = false; 164 165 if (table->pmu) 166 test = &test_uncore_events[0]; 167 else 168 test = &test_cpu_events[0]; 169 170 te = &test->event; 171 172 for (; te->name; test++, te = &test->event) { 173 if (strcmp(table->name, te->name)) 174 continue; 175 found = true; 176 map_events++; 177 178 if (!is_same(table->desc, te->desc)) { 179 pr_debug2("testing event table %s: mismatched desc, %s vs %s\n", 180 table->name, table->desc, te->desc); 181 return -1; 182 } 183 184 if (!is_same(table->topic, te->topic)) { 185 pr_debug2("testing event table %s: mismatched topic, %s vs %s\n", 186 table->name, table->topic, 187 te->topic); 188 return -1; 189 } 190 191 if (!is_same(table->long_desc, te->long_desc)) { 192 pr_debug2("testing event table %s: mismatched long_desc, %s vs %s\n", 193 table->name, table->long_desc, 194 te->long_desc); 195 return -1; 196 } 197 198 if (!is_same(table->unit, te->unit)) { 199 pr_debug2("testing event table %s: mismatched unit, %s vs %s\n", 200 table->name, table->unit, 201 te->unit); 202 return -1; 203 } 204 205 if (!is_same(table->perpkg, te->perpkg)) { 206 pr_debug2("testing event table %s: mismatched perpkg, %s vs %s\n", 207 table->name, table->perpkg, 208 te->perpkg); 209 return -1; 210 } 211 212 if (!is_same(table->metric_expr, te->metric_expr)) { 213 pr_debug2("testing event table %s: mismatched metric_expr, %s vs %s\n", 214 table->name, table->metric_expr, 215 te->metric_expr); 216 return -1; 217 } 218 219 if (!is_same(table->metric_name, te->metric_name)) { 220 pr_debug2("testing event table %s: mismatched metric_name, %s vs %s\n", 221 table->name, table->metric_name, 222 te->metric_name); 223 return -1; 224 } 225 226 if (!is_same(table->deprecated, te->deprecated)) { 227 pr_debug2("testing event table %s: mismatched deprecated, %s vs %s\n", 228 table->name, table->deprecated, 229 te->deprecated); 230 return -1; 231 } 232 233 pr_debug("testing event table %s: pass\n", table->name); 234 } 235 236 if (!found) { 237 pr_err("testing event table: could not find event %s\n", 238 table->name); 239 return -1; 240 } 241 } 242 243 if (map_events != expected_events) { 244 pr_err("testing event table: found %d, but expected %d\n", 245 map_events, expected_events); 246 return -1; 247 } 248 249 return 0; 250 } 251 252 static struct perf_pmu_alias *find_alias(const char *test_event, struct list_head *aliases) 253 { 254 struct perf_pmu_alias *alias; 255 256 list_for_each_entry(alias, aliases, list) 257 if (!strcmp(test_event, alias->name)) 258 return alias; 259 260 return NULL; 261 } 262 263 /* Verify aliases are as expected */ 264 static int __test__pmu_event_aliases(char *pmu_name, int *count) 265 { 266 struct perf_pmu_test_event *test; 267 struct pmu_event *te; 268 struct perf_pmu *pmu; 269 LIST_HEAD(aliases); 270 int res = 0; 271 bool use_uncore_table; 272 struct pmu_events_map *map = __test_pmu_get_events_map(); 273 274 if (!map) 275 return -1; 276 277 if (is_pmu_core(pmu_name)) { 278 test = &test_cpu_events[0]; 279 use_uncore_table = false; 280 } else { 281 test = &test_uncore_events[0]; 282 use_uncore_table = true; 283 } 284 285 pmu = zalloc(sizeof(*pmu)); 286 if (!pmu) 287 return -1; 288 289 pmu->name = pmu_name; 290 291 pmu_add_cpu_aliases_map(&aliases, pmu, map); 292 293 for (te = &test->event; te->name; test++, te = &test->event) { 294 struct perf_pmu_alias *alias = find_alias(te->name, &aliases); 295 296 if (!alias) { 297 bool uncore_match = pmu_uncore_alias_match(pmu_name, 298 te->pmu); 299 300 if (use_uncore_table && !uncore_match) { 301 pr_debug3("testing aliases PMU %s: skip matching alias %s\n", 302 pmu_name, te->name); 303 continue; 304 } 305 306 pr_debug2("testing aliases PMU %s: no alias, alias_table->name=%s\n", 307 pmu_name, te->name); 308 res = -1; 309 break; 310 } 311 312 if (!is_same(alias->desc, te->desc)) { 313 pr_debug2("testing aliases PMU %s: mismatched desc, %s vs %s\n", 314 pmu_name, alias->desc, te->desc); 315 res = -1; 316 break; 317 } 318 319 if (!is_same(alias->long_desc, test->alias_long_desc)) { 320 pr_debug2("testing aliases PMU %s: mismatched long_desc, %s vs %s\n", 321 pmu_name, alias->long_desc, 322 test->alias_long_desc); 323 res = -1; 324 break; 325 } 326 327 if (!is_same(alias->str, test->alias_str)) { 328 pr_debug2("testing aliases PMU %s: mismatched str, %s vs %s\n", 329 pmu_name, alias->str, test->alias_str); 330 res = -1; 331 break; 332 } 333 334 if (!is_same(alias->topic, te->topic)) { 335 pr_debug2("testing aliases PMU %s: mismatched topic, %s vs %s\n", 336 pmu_name, alias->topic, te->topic); 337 res = -1; 338 break; 339 } 340 341 (*count)++; 342 pr_debug2("testing aliases PMU %s: matched event %s\n", 343 pmu_name, alias->name); 344 } 345 346 free(pmu); 347 return res; 348 } 349 350 int test__pmu_events(struct test *test __maybe_unused, 351 int subtest __maybe_unused) 352 { 353 struct perf_pmu *pmu = NULL; 354 355 if (__test_pmu_event_table()) 356 return -1; 357 358 while ((pmu = perf_pmu__scan(pmu)) != NULL) { 359 int count = 0; 360 361 if (list_empty(&pmu->format)) { 362 pr_debug2("skipping testing PMU %s\n", pmu->name); 363 continue; 364 } 365 366 if (__test__pmu_event_aliases(pmu->name, &count)) { 367 pr_debug("testing PMU %s aliases: failed\n", pmu->name); 368 return -1; 369 } 370 371 if (count == 0) 372 pr_debug3("testing PMU %s aliases: no events to match\n", 373 pmu->name); 374 else 375 pr_debug("testing PMU %s aliases: pass\n", pmu->name); 376 } 377 378 return 0; 379 } 380