1 // SPDX-License-Identifier: GPL-2.0 2 #include "arch-tests.h" 3 #include "debug.h" 4 #include "evlist.h" 5 #include "evsel.h" 6 #include "pmu-hybrid.h" 7 #include "tests/tests.h" 8 9 static bool test_config(const struct evsel *evsel, __u64 expected_config) 10 { 11 return (evsel->core.attr.config & PERF_HW_EVENT_MASK) == expected_config; 12 } 13 14 static bool test_perf_config(const struct perf_evsel *evsel, __u64 expected_config) 15 { 16 return (evsel->attr.config & PERF_HW_EVENT_MASK) == expected_config; 17 } 18 19 static bool test_hybrid_type(const struct evsel *evsel, __u64 expected_config) 20 { 21 return (evsel->core.attr.config >> PERF_PMU_TYPE_SHIFT) == expected_config; 22 } 23 24 static int test__hybrid_hw_event_with_pmu(struct evlist *evlist) 25 { 26 struct evsel *evsel = evlist__first(evlist); 27 28 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); 29 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); 30 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); 31 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); 32 return TEST_OK; 33 } 34 35 static int test__hybrid_hw_group_event(struct evlist *evlist) 36 { 37 struct evsel *evsel, *leader; 38 39 evsel = leader = evlist__first(evlist); 40 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); 41 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); 42 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); 43 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); 44 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); 45 46 evsel = evsel__next(evsel); 47 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); 48 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); 49 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS)); 50 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); 51 return TEST_OK; 52 } 53 54 static int test__hybrid_sw_hw_group_event(struct evlist *evlist) 55 { 56 struct evsel *evsel, *leader; 57 58 evsel = leader = evlist__first(evlist); 59 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); 60 TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); 61 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); 62 63 evsel = evsel__next(evsel); 64 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); 65 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); 66 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); 67 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); 68 return TEST_OK; 69 } 70 71 static int test__hybrid_hw_sw_group_event(struct evlist *evlist) 72 { 73 struct evsel *evsel, *leader; 74 75 evsel = leader = evlist__first(evlist); 76 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); 77 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); 78 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); 79 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); 80 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); 81 82 evsel = evsel__next(evsel); 83 TEST_ASSERT_VAL("wrong type", PERF_TYPE_SOFTWARE == evsel->core.attr.type); 84 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); 85 return TEST_OK; 86 } 87 88 static int test__hybrid_group_modifier1(struct evlist *evlist) 89 { 90 struct evsel *evsel, *leader; 91 92 evsel = leader = evlist__first(evlist); 93 TEST_ASSERT_VAL("wrong number of entries", 2 == evlist->core.nr_entries); 94 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); 95 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); 96 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_CPU_CYCLES)); 97 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); 98 TEST_ASSERT_VAL("wrong exclude_user", evsel->core.attr.exclude_user); 99 TEST_ASSERT_VAL("wrong exclude_kernel", !evsel->core.attr.exclude_kernel); 100 101 evsel = evsel__next(evsel); 102 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HARDWARE == evsel->core.attr.type); 103 TEST_ASSERT_VAL("wrong hybrid type", test_hybrid_type(evsel, PERF_TYPE_RAW)); 104 TEST_ASSERT_VAL("wrong config", test_config(evsel, PERF_COUNT_HW_INSTRUCTIONS)); 105 TEST_ASSERT_VAL("wrong leader", evsel__has_leader(evsel, leader)); 106 TEST_ASSERT_VAL("wrong exclude_user", !evsel->core.attr.exclude_user); 107 TEST_ASSERT_VAL("wrong exclude_kernel", evsel->core.attr.exclude_kernel); 108 return TEST_OK; 109 } 110 111 static int test__hybrid_raw1(struct evlist *evlist) 112 { 113 struct perf_evsel *evsel; 114 115 perf_evlist__for_each_evsel(&evlist->core, evsel) { 116 struct perf_pmu *pmu = perf_pmu__find_by_type(evsel->attr.type); 117 118 TEST_ASSERT_VAL("missing pmu", pmu); 119 TEST_ASSERT_VAL("unexpected pmu", !strncmp(pmu->name, "cpu_", 4)); 120 TEST_ASSERT_VAL("wrong config", test_perf_config(evsel, 0x1a)); 121 } 122 return TEST_OK; 123 } 124 125 static int test__hybrid_raw2(struct evlist *evlist) 126 { 127 struct evsel *evsel = evlist__first(evlist); 128 129 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); 130 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); 131 TEST_ASSERT_VAL("wrong config", test_config(evsel, 0x1a)); 132 return TEST_OK; 133 } 134 135 static int test__hybrid_cache_event(struct evlist *evlist) 136 { 137 struct evsel *evsel = evlist__first(evlist); 138 139 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); 140 TEST_ASSERT_VAL("wrong type", PERF_TYPE_HW_CACHE == evsel->core.attr.type); 141 TEST_ASSERT_VAL("wrong config", 0x2 == (evsel->core.attr.config & 0xffffffff)); 142 return TEST_OK; 143 } 144 145 static int test__checkevent_pmu(struct evlist *evlist) 146 { 147 148 struct evsel *evsel = evlist__first(evlist); 149 150 TEST_ASSERT_VAL("wrong number of entries", 1 == evlist->core.nr_entries); 151 TEST_ASSERT_VAL("wrong type", PERF_TYPE_RAW == evsel->core.attr.type); 152 TEST_ASSERT_VAL("wrong config", 10 == evsel->core.attr.config); 153 TEST_ASSERT_VAL("wrong config1", 1 == evsel->core.attr.config1); 154 TEST_ASSERT_VAL("wrong config2", 3 == evsel->core.attr.config2); 155 TEST_ASSERT_VAL("wrong config3", 0 == evsel->core.attr.config3); 156 /* 157 * The period value gets configured within evlist__config, 158 * while this test executes only parse events method. 159 */ 160 TEST_ASSERT_VAL("wrong period", 0 == evsel->core.attr.sample_period); 161 162 return TEST_OK; 163 } 164 165 struct evlist_test { 166 const char *name; 167 bool (*valid)(void); 168 int (*check)(struct evlist *evlist); 169 }; 170 171 static const struct evlist_test test__hybrid_events[] = { 172 { 173 .name = "cpu_core/cpu-cycles/", 174 .check = test__hybrid_hw_event_with_pmu, 175 /* 0 */ 176 }, 177 { 178 .name = "{cpu_core/cpu-cycles/,cpu_core/instructions/}", 179 .check = test__hybrid_hw_group_event, 180 /* 1 */ 181 }, 182 { 183 .name = "{cpu-clock,cpu_core/cpu-cycles/}", 184 .check = test__hybrid_sw_hw_group_event, 185 /* 2 */ 186 }, 187 { 188 .name = "{cpu_core/cpu-cycles/,cpu-clock}", 189 .check = test__hybrid_hw_sw_group_event, 190 /* 3 */ 191 }, 192 { 193 .name = "{cpu_core/cpu-cycles/k,cpu_core/instructions/u}", 194 .check = test__hybrid_group_modifier1, 195 /* 4 */ 196 }, 197 { 198 .name = "r1a", 199 .check = test__hybrid_raw1, 200 /* 5 */ 201 }, 202 { 203 .name = "cpu_core/r1a/", 204 .check = test__hybrid_raw2, 205 /* 6 */ 206 }, 207 { 208 .name = "cpu_core/config=10,config1,config2=3,period=1000/u", 209 .check = test__checkevent_pmu, 210 /* 7 */ 211 }, 212 { 213 .name = "cpu_core/LLC-loads/", 214 .check = test__hybrid_cache_event, 215 /* 8 */ 216 }, 217 }; 218 219 static int test_event(const struct evlist_test *e) 220 { 221 struct parse_events_error err; 222 struct evlist *evlist; 223 int ret; 224 225 if (e->valid && !e->valid()) { 226 pr_debug("... SKIP\n"); 227 return TEST_OK; 228 } 229 230 evlist = evlist__new(); 231 if (evlist == NULL) { 232 pr_err("Failed allocation"); 233 return TEST_FAIL; 234 } 235 parse_events_error__init(&err); 236 ret = parse_events(evlist, e->name, &err); 237 if (ret) { 238 pr_debug("failed to parse event '%s', err %d, str '%s'\n", 239 e->name, ret, err.str); 240 parse_events_error__print(&err, e->name); 241 ret = TEST_FAIL; 242 if (strstr(err.str, "can't access trace events")) 243 ret = TEST_SKIP; 244 } else { 245 ret = e->check(evlist); 246 } 247 parse_events_error__exit(&err); 248 evlist__delete(evlist); 249 250 return ret; 251 } 252 253 static int combine_test_results(int existing, int latest) 254 { 255 if (existing == TEST_FAIL) 256 return TEST_FAIL; 257 if (existing == TEST_SKIP) 258 return latest == TEST_OK ? TEST_SKIP : latest; 259 return latest; 260 } 261 262 static int test_events(const struct evlist_test *events, int cnt) 263 { 264 int ret = TEST_OK; 265 266 for (int i = 0; i < cnt; i++) { 267 const struct evlist_test *e = &events[i]; 268 int test_ret; 269 270 pr_debug("running test %d '%s'\n", i, e->name); 271 test_ret = test_event(e); 272 if (test_ret != TEST_OK) { 273 pr_debug("Event test failure: test %d '%s'", i, e->name); 274 ret = combine_test_results(ret, test_ret); 275 } 276 } 277 278 return ret; 279 } 280 281 int test__hybrid(struct test_suite *test __maybe_unused, int subtest __maybe_unused) 282 { 283 if (!perf_pmu__has_hybrid()) 284 return TEST_SKIP; 285 286 return test_events(test__hybrid_events, ARRAY_SIZE(test__hybrid_events)); 287 } 288