1 // SPDX-License-Identifier: GPL-2.0 2 #include <errno.h> 3 #include <fcntl.h> 4 #include <inttypes.h> 5 #include <stdlib.h> 6 #include <perf/cpumap.h> 7 8 #include "cpumap.h" 9 #include "debug.h" 10 #include "event.h" 11 #include "evlist.h" 12 #include "evsel.h" 13 #include "thread_map.h" 14 #include "tests.h" 15 #include "util/affinity.h" 16 #include "util/mmap.h" 17 #include "util/sample.h" 18 #include <linux/err.h> 19 #include <linux/kernel.h> 20 #include <linux/string.h> 21 #include <perf/evlist.h> 22 #include <perf/mmap.h> 23 24 /* 25 * This test will generate random numbers of calls to some getpid syscalls, 26 * then establish an mmap for a group of events that are created to monitor 27 * the syscalls. 28 * 29 * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated 30 * sample.id field to map back to its respective perf_evsel instance. 31 * 32 * Then it checks if the number of syscalls reported as perf events by 33 * the kernel corresponds to the number of syscalls made. 34 */ 35 static int test__basic_mmap(struct test_suite *test __maybe_unused, int subtest __maybe_unused) 36 { 37 int err = TEST_FAIL; 38 union perf_event *event; 39 struct perf_thread_map *threads; 40 struct perf_cpu_map *cpus; 41 struct evlist *evlist; 42 cpu_set_t cpu_set; 43 const char *syscall_names[] = { "getsid", "getppid", "getpgid", }; 44 pid_t (*syscalls[])(void) = { (void *)getsid, getppid, (void*)getpgid }; 45 #define nsyscalls ARRAY_SIZE(syscall_names) 46 unsigned int nr_events[nsyscalls], 47 expected_nr_events[nsyscalls], i, j; 48 struct evsel *evsels[nsyscalls], *evsel; 49 char sbuf[STRERR_BUFSIZE]; 50 struct mmap *md; 51 52 threads = thread_map__new_by_tid(getpid()); 53 if (threads == NULL) { 54 pr_debug("thread_map__new\n"); 55 return -1; 56 } 57 58 cpus = perf_cpu_map__new_online_cpus(); 59 if (cpus == NULL) { 60 pr_debug("perf_cpu_map__new\n"); 61 goto out_free_threads; 62 } 63 64 CPU_ZERO(&cpu_set); 65 CPU_SET(perf_cpu_map__cpu(cpus, 0).cpu, &cpu_set); 66 sched_setaffinity(0, sizeof(cpu_set), &cpu_set); 67 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) { 68 pr_debug("sched_setaffinity() failed on CPU %d: %s ", 69 perf_cpu_map__cpu(cpus, 0).cpu, 70 str_error_r(errno, sbuf, sizeof(sbuf))); 71 goto out_free_cpus; 72 } 73 74 evlist = evlist__new(); 75 if (evlist == NULL) { 76 pr_debug("evlist__new\n"); 77 goto out_free_cpus; 78 } 79 80 perf_evlist__set_maps(&evlist->core, cpus, threads); 81 82 for (i = 0; i < nsyscalls; ++i) { 83 char name[64]; 84 85 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]); 86 evsels[i] = evsel__newtp("syscalls", name); 87 if (IS_ERR(evsels[i])) { 88 pr_debug("evsel__new(%s)\n", name); 89 if (PTR_ERR(evsels[i]) == -EACCES) { 90 /* Permissions failure, flag the failure as a skip. */ 91 err = TEST_SKIP; 92 } 93 goto out_delete_evlist; 94 } 95 96 evsels[i]->core.attr.wakeup_events = 1; 97 evsel__set_sample_id(evsels[i], false); 98 99 evlist__add(evlist, evsels[i]); 100 101 if (evsel__open(evsels[i], cpus, threads) < 0) { 102 pr_debug("failed to open counter: %s, " 103 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 104 str_error_r(errno, sbuf, sizeof(sbuf))); 105 goto out_delete_evlist; 106 } 107 108 nr_events[i] = 0; 109 expected_nr_events[i] = 1 + rand() % 127; 110 } 111 112 if (evlist__mmap(evlist, 128) < 0) { 113 pr_debug("failed to mmap events: %d (%s)\n", errno, 114 str_error_r(errno, sbuf, sizeof(sbuf))); 115 goto out_delete_evlist; 116 } 117 118 for (i = 0; i < nsyscalls; ++i) 119 for (j = 0; j < expected_nr_events[i]; ++j) { 120 syscalls[i](); 121 } 122 123 md = &evlist->mmap[0]; 124 if (perf_mmap__read_init(&md->core) < 0) 125 goto out_init; 126 127 while ((event = perf_mmap__read_event(&md->core)) != NULL) { 128 struct perf_sample sample; 129 130 if (event->header.type != PERF_RECORD_SAMPLE) { 131 pr_debug("unexpected %s event\n", 132 perf_event__name(event->header.type)); 133 goto out_delete_evlist; 134 } 135 136 perf_sample__init(&sample, /*all=*/false); 137 err = evlist__parse_sample(evlist, event, &sample); 138 if (err) { 139 pr_err("Can't parse sample, err = %d\n", err); 140 perf_sample__exit(&sample); 141 goto out_delete_evlist; 142 } 143 144 err = -1; 145 evsel = sample.evsel; 146 if (!evsel) 147 evsel = evlist__id2evsel(evlist, sample.id); 148 perf_sample__exit(&sample); 149 if (evsel == NULL) { 150 pr_debug("event with id %" PRIu64 151 " doesn't map to an evsel\n", sample.id); 152 goto out_delete_evlist; 153 } 154 nr_events[evsel->core.idx]++; 155 perf_mmap__consume(&md->core); 156 } 157 perf_mmap__read_done(&md->core); 158 159 out_init: 160 err = 0; 161 evlist__for_each_entry(evlist, evsel) { 162 if (nr_events[evsel->core.idx] != expected_nr_events[evsel->core.idx]) { 163 pr_debug("expected %d %s events, got %d\n", 164 expected_nr_events[evsel->core.idx], 165 evsel__name(evsel), nr_events[evsel->core.idx]); 166 err = -1; 167 goto out_delete_evlist; 168 } 169 } 170 171 out_delete_evlist: 172 evlist__delete(evlist); 173 out_free_cpus: 174 perf_cpu_map__put(cpus); 175 out_free_threads: 176 perf_thread_map__put(threads); 177 return err; 178 } 179 180 enum user_read_state { 181 USER_READ_ENABLED, 182 USER_READ_DISABLED, 183 USER_READ_UNKNOWN, 184 }; 185 186 static enum user_read_state set_user_read(struct perf_pmu *pmu, enum user_read_state enabled) 187 { 188 char buf[2] = {0, '\n'}; 189 ssize_t len; 190 int events_fd, rdpmc_fd; 191 enum user_read_state old_user_read = USER_READ_UNKNOWN; 192 193 if (enabled == USER_READ_UNKNOWN) 194 return USER_READ_UNKNOWN; 195 196 events_fd = perf_pmu__event_source_devices_fd(); 197 if (events_fd < 0) 198 return USER_READ_UNKNOWN; 199 200 rdpmc_fd = perf_pmu__pathname_fd(events_fd, pmu->name, "rdpmc", O_RDWR); 201 if (rdpmc_fd < 0) { 202 close(events_fd); 203 return USER_READ_UNKNOWN; 204 } 205 206 len = read(rdpmc_fd, buf, sizeof(buf)); 207 if (len != sizeof(buf)) 208 pr_debug("%s read failed\n", __func__); 209 210 // Note, on Intel hybrid disabling on 1 PMU will implicitly disable on 211 // all the core PMUs. 212 old_user_read = (buf[0] == '1') ? USER_READ_ENABLED : USER_READ_DISABLED; 213 214 if (enabled != old_user_read) { 215 buf[0] = (enabled == USER_READ_ENABLED) ? '1' : '0'; 216 len = write(rdpmc_fd, buf, sizeof(buf)); 217 if (len != sizeof(buf)) 218 pr_debug("%s write failed\n", __func__); 219 } 220 close(rdpmc_fd); 221 close(events_fd); 222 return old_user_read; 223 } 224 225 static int test_stat_user_read(u64 event, enum user_read_state enabled) 226 { 227 struct perf_pmu *pmu = NULL; 228 struct perf_thread_map *threads = perf_thread_map__new_dummy(); 229 int ret = TEST_OK; 230 231 pr_err("User space counter reading %" PRIu64 "\n", event); 232 if (!threads) { 233 pr_err("User space counter reading [Failed to create threads]\n"); 234 return TEST_FAIL; 235 } 236 perf_thread_map__set_pid(threads, 0, 0); 237 238 while ((pmu = perf_pmus__scan_core(pmu)) != NULL) { 239 enum user_read_state saved_user_read_state = set_user_read(pmu, enabled); 240 struct perf_event_attr attr = { 241 .type = PERF_TYPE_HARDWARE, 242 .config = perf_pmus__supports_extended_type() 243 ? event | ((u64)pmu->type << PERF_PMU_TYPE_SHIFT) 244 : event, 245 #ifdef __aarch64__ 246 .config1 = 0x2, /* Request user access */ 247 #endif 248 }; 249 struct perf_evsel *evsel = NULL; 250 int err; 251 struct perf_event_mmap_page *pc; 252 bool mapped = false, opened = false, rdpmc_supported; 253 struct perf_counts_values counts = { .val = 0 }; 254 255 256 pr_debug("User space counter reading for PMU %s\n", pmu->name); 257 /* 258 * Restrict scheduling to only use the rdpmc on the CPUs the 259 * event can be on. If the test doesn't run on the CPU of the 260 * event then the event will be disabled and the pc->index test 261 * will fail. 262 */ 263 if (pmu->cpus != NULL) 264 cpu_map__set_affinity(pmu->cpus); 265 266 /* Make the evsel. */ 267 evsel = perf_evsel__new(&attr); 268 if (!evsel) { 269 pr_err("User space counter reading for PMU %s [Failed to allocate evsel]\n", 270 pmu->name); 271 ret = TEST_FAIL; 272 goto cleanup; 273 } 274 275 err = perf_evsel__open(evsel, NULL, threads); 276 if (err) { 277 pr_err("User space counter reading for PMU %s [Failed to open evsel]\n", 278 pmu->name); 279 ret = TEST_SKIP; 280 goto cleanup; 281 } 282 opened = true; 283 err = perf_evsel__mmap(evsel, 0); 284 if (err) { 285 pr_err("User space counter reading for PMU %s [Failed to mmap evsel]\n", 286 pmu->name); 287 ret = TEST_FAIL; 288 goto cleanup; 289 } 290 mapped = true; 291 292 pc = perf_evsel__mmap_base(evsel, 0, 0); 293 if (!pc) { 294 pr_err("User space counter reading for PMU %s [Failed to get mmaped address]\n", 295 pmu->name); 296 ret = TEST_FAIL; 297 goto cleanup; 298 } 299 300 if (saved_user_read_state == USER_READ_UNKNOWN) 301 rdpmc_supported = pc->cap_user_rdpmc && pc->index; 302 else 303 rdpmc_supported = (enabled == USER_READ_ENABLED); 304 305 if (rdpmc_supported && (!pc->cap_user_rdpmc || !pc->index)) { 306 pr_err("User space counter reading for PMU %s [Failed unexpected supported counter access %d %d]\n", 307 pmu->name, pc->cap_user_rdpmc, pc->index); 308 ret = TEST_FAIL; 309 goto cleanup; 310 } 311 312 if (!rdpmc_supported && pc->cap_user_rdpmc) { 313 pr_err("User space counter reading for PMU %s [Failed unexpected unsupported counter access %d]\n", 314 pmu->name, pc->cap_user_rdpmc); 315 ret = TEST_FAIL; 316 goto cleanup; 317 } 318 319 if (rdpmc_supported && pc->pmc_width < 32) { 320 pr_err("User space counter reading for PMU %s [Failed width not set %d]\n", 321 pmu->name, pc->pmc_width); 322 ret = TEST_FAIL; 323 goto cleanup; 324 } 325 326 perf_evsel__read(evsel, 0, 0, &counts); 327 if (rdpmc_supported && counts.val == 0) { 328 pr_err("User space counter reading for PMU %s [Failed read]\n", pmu->name); 329 ret = TEST_FAIL; 330 goto cleanup; 331 } 332 333 for (int i = 0; i < 5; i++) { 334 volatile int count = 0x10000 << i; 335 __u64 start, end, last = 0; 336 337 pr_debug("\tloop = %u, ", count); 338 339 perf_evsel__read(evsel, 0, 0, &counts); 340 start = counts.val; 341 342 while (count--) ; 343 344 perf_evsel__read(evsel, 0, 0, &counts); 345 end = counts.val; 346 347 if ((end - start) < last) { 348 pr_err("User space counter reading for PMU %s [Failed invalid counter data: end=%llu start=%llu last= %llu]\n", 349 pmu->name, end, start, last); 350 ret = TEST_FAIL; 351 goto cleanup; 352 } 353 last = end - start; 354 pr_debug("count = %llu\n", last); 355 } 356 pr_debug("User space counter reading for PMU %s [Success]\n", pmu->name); 357 cleanup: 358 if (mapped) 359 perf_evsel__munmap(evsel); 360 if (opened) 361 perf_evsel__close(evsel); 362 perf_evsel__delete(evsel); 363 364 /* If the affinity was changed, then put it back to all CPUs. */ 365 if (pmu->cpus != NULL) { 366 struct perf_cpu_map *cpus = cpu_map__online(); 367 368 cpu_map__set_affinity(cpus); 369 perf_cpu_map__put(cpus); 370 } 371 set_user_read(pmu, saved_user_read_state); 372 } 373 perf_thread_map__put(threads); 374 return ret; 375 } 376 377 static int test__mmap_user_read_instr(struct test_suite *test __maybe_unused, 378 int subtest __maybe_unused) 379 { 380 return test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS, USER_READ_ENABLED); 381 } 382 383 static int test__mmap_user_read_cycles(struct test_suite *test __maybe_unused, 384 int subtest __maybe_unused) 385 { 386 return test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES, USER_READ_ENABLED); 387 } 388 389 static int test__mmap_user_read_instr_disabled(struct test_suite *test __maybe_unused, 390 int subtest __maybe_unused) 391 { 392 return test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS, USER_READ_DISABLED); 393 } 394 395 static int test__mmap_user_read_cycles_disabled(struct test_suite *test __maybe_unused, 396 int subtest __maybe_unused) 397 { 398 return test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES, USER_READ_DISABLED); 399 } 400 401 static struct test_case tests__basic_mmap[] = { 402 TEST_CASE_REASON("Read samples using the mmap interface", 403 basic_mmap, 404 "permissions"), 405 TEST_CASE_REASON_EXCLUSIVE("User space counter reading of instructions", 406 mmap_user_read_instr, 407 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \ 408 (defined(__riscv) && __riscv_xlen == 64) 409 "permissions" 410 #else 411 "unsupported" 412 #endif 413 ), 414 TEST_CASE_REASON_EXCLUSIVE("User space counter reading of cycles", 415 mmap_user_read_cycles, 416 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \ 417 (defined(__riscv) && __riscv_xlen == 64) 418 "permissions" 419 #else 420 "unsupported" 421 #endif 422 ), 423 TEST_CASE_REASON_EXCLUSIVE("User space counter disabling instructions", 424 mmap_user_read_instr_disabled, 425 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \ 426 (defined(__riscv) && __riscv_xlen == 64) 427 "permissions" 428 #else 429 "unsupported" 430 #endif 431 ), 432 TEST_CASE_REASON_EXCLUSIVE("User space counter disabling cycles", 433 mmap_user_read_cycles_disabled, 434 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \ 435 (defined(__riscv) && __riscv_xlen == 64) 436 "permissions" 437 #else 438 "unsupported" 439 #endif 440 ), 441 { .name = NULL, } 442 }; 443 444 struct test_suite suite__basic_mmap = { 445 .desc = "mmap interface tests", 446 .test_cases = tests__basic_mmap, 447 }; 448