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