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