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 = evlist__id2evsel(evlist, sample.id); 146 perf_sample__exit(&sample); 147 if (evsel == NULL) { 148 pr_debug("event with id %" PRIu64 149 " doesn't map to an evsel\n", sample.id); 150 goto out_delete_evlist; 151 } 152 nr_events[evsel->core.idx]++; 153 perf_mmap__consume(&md->core); 154 } 155 perf_mmap__read_done(&md->core); 156 157 out_init: 158 err = 0; 159 evlist__for_each_entry(evlist, evsel) { 160 if (nr_events[evsel->core.idx] != expected_nr_events[evsel->core.idx]) { 161 pr_debug("expected %d %s events, got %d\n", 162 expected_nr_events[evsel->core.idx], 163 evsel__name(evsel), nr_events[evsel->core.idx]); 164 err = -1; 165 goto out_delete_evlist; 166 } 167 } 168 169 out_delete_evlist: 170 evlist__delete(evlist); 171 out_free_cpus: 172 perf_cpu_map__put(cpus); 173 out_free_threads: 174 perf_thread_map__put(threads); 175 return err; 176 } 177 178 enum user_read_state { 179 USER_READ_ENABLED, 180 USER_READ_DISABLED, 181 USER_READ_UNKNOWN, 182 }; 183 184 static enum user_read_state set_user_read(struct perf_pmu *pmu, enum user_read_state enabled) 185 { 186 char buf[2] = {0, '\n'}; 187 ssize_t len; 188 int events_fd, rdpmc_fd; 189 enum user_read_state old_user_read = USER_READ_UNKNOWN; 190 191 if (enabled == USER_READ_UNKNOWN) 192 return USER_READ_UNKNOWN; 193 194 events_fd = perf_pmu__event_source_devices_fd(); 195 if (events_fd < 0) 196 return USER_READ_UNKNOWN; 197 198 rdpmc_fd = perf_pmu__pathname_fd(events_fd, pmu->name, "rdpmc", O_RDWR); 199 if (rdpmc_fd < 0) { 200 close(events_fd); 201 return USER_READ_UNKNOWN; 202 } 203 204 len = read(rdpmc_fd, buf, sizeof(buf)); 205 if (len != sizeof(buf)) 206 pr_debug("%s read failed\n", __func__); 207 208 // Note, on Intel hybrid disabling on 1 PMU will implicitly disable on 209 // all the core PMUs. 210 old_user_read = (buf[0] == '1') ? USER_READ_ENABLED : USER_READ_DISABLED; 211 212 if (enabled != old_user_read) { 213 buf[0] = (enabled == USER_READ_ENABLED) ? '1' : '0'; 214 len = write(rdpmc_fd, buf, sizeof(buf)); 215 if (len != sizeof(buf)) 216 pr_debug("%s write failed\n", __func__); 217 } 218 close(rdpmc_fd); 219 close(events_fd); 220 return old_user_read; 221 } 222 223 static int test_stat_user_read(u64 event, enum user_read_state enabled) 224 { 225 struct perf_pmu *pmu = NULL; 226 struct perf_thread_map *threads = perf_thread_map__new_dummy(); 227 int ret = TEST_OK; 228 229 pr_err("User space counter reading %" PRIu64 "\n", event); 230 if (!threads) { 231 pr_err("User space counter reading [Failed to create threads]\n"); 232 return TEST_FAIL; 233 } 234 perf_thread_map__set_pid(threads, 0, 0); 235 236 while ((pmu = perf_pmus__scan_core(pmu)) != NULL) { 237 enum user_read_state saved_user_read_state = set_user_read(pmu, enabled); 238 struct perf_event_attr attr = { 239 .type = PERF_TYPE_HARDWARE, 240 .config = perf_pmus__supports_extended_type() 241 ? event | ((u64)pmu->type << PERF_PMU_TYPE_SHIFT) 242 : event, 243 #ifdef __aarch64__ 244 .config1 = 0x2, /* Request user access */ 245 #endif 246 }; 247 struct perf_evsel *evsel = NULL; 248 int err; 249 struct perf_event_mmap_page *pc; 250 bool mapped = false, opened = false, rdpmc_supported; 251 struct perf_counts_values counts = { .val = 0 }; 252 253 254 pr_debug("User space counter reading for PMU %s\n", pmu->name); 255 /* 256 * Restrict scheduling to only use the rdpmc on the CPUs the 257 * event can be on. If the test doesn't run on the CPU of the 258 * event then the event will be disabled and the pc->index test 259 * will fail. 260 */ 261 if (pmu->cpus != NULL) 262 cpu_map__set_affinity(pmu->cpus); 263 264 /* Make the evsel. */ 265 evsel = perf_evsel__new(&attr); 266 if (!evsel) { 267 pr_err("User space counter reading for PMU %s [Failed to allocate evsel]\n", 268 pmu->name); 269 ret = TEST_FAIL; 270 goto cleanup; 271 } 272 273 err = perf_evsel__open(evsel, NULL, threads); 274 if (err) { 275 pr_err("User space counter reading for PMU %s [Failed to open evsel]\n", 276 pmu->name); 277 ret = TEST_SKIP; 278 goto cleanup; 279 } 280 opened = true; 281 err = perf_evsel__mmap(evsel, 0); 282 if (err) { 283 pr_err("User space counter reading for PMU %s [Failed to mmap evsel]\n", 284 pmu->name); 285 ret = TEST_FAIL; 286 goto cleanup; 287 } 288 mapped = true; 289 290 pc = perf_evsel__mmap_base(evsel, 0, 0); 291 if (!pc) { 292 pr_err("User space counter reading for PMU %s [Failed to get mmaped address]\n", 293 pmu->name); 294 ret = TEST_FAIL; 295 goto cleanup; 296 } 297 298 if (saved_user_read_state == USER_READ_UNKNOWN) 299 rdpmc_supported = pc->cap_user_rdpmc && pc->index; 300 else 301 rdpmc_supported = (enabled == USER_READ_ENABLED); 302 303 if (rdpmc_supported && (!pc->cap_user_rdpmc || !pc->index)) { 304 pr_err("User space counter reading for PMU %s [Failed unexpected supported counter access %d %d]\n", 305 pmu->name, pc->cap_user_rdpmc, pc->index); 306 ret = TEST_FAIL; 307 goto cleanup; 308 } 309 310 if (!rdpmc_supported && pc->cap_user_rdpmc) { 311 pr_err("User space counter reading for PMU %s [Failed unexpected unsupported counter access %d]\n", 312 pmu->name, pc->cap_user_rdpmc); 313 ret = TEST_FAIL; 314 goto cleanup; 315 } 316 317 if (rdpmc_supported && pc->pmc_width < 32) { 318 pr_err("User space counter reading for PMU %s [Failed width not set %d]\n", 319 pmu->name, pc->pmc_width); 320 ret = TEST_FAIL; 321 goto cleanup; 322 } 323 324 perf_evsel__read(evsel, 0, 0, &counts); 325 if (counts.val == 0) { 326 pr_err("User space counter reading for PMU %s [Failed read]\n", pmu->name); 327 ret = TEST_FAIL; 328 goto cleanup; 329 } 330 331 for (int i = 0; i < 5; i++) { 332 volatile int count = 0x10000 << i; 333 __u64 start, end, last = 0; 334 335 pr_debug("\tloop = %u, ", count); 336 337 perf_evsel__read(evsel, 0, 0, &counts); 338 start = counts.val; 339 340 while (count--) ; 341 342 perf_evsel__read(evsel, 0, 0, &counts); 343 end = counts.val; 344 345 if ((end - start) < last) { 346 pr_err("User space counter reading for PMU %s [Failed invalid counter data: end=%llu start=%llu last= %llu]\n", 347 pmu->name, end, start, last); 348 ret = TEST_FAIL; 349 goto cleanup; 350 } 351 last = end - start; 352 pr_debug("count = %llu\n", last); 353 } 354 pr_debug("User space counter reading for PMU %s [Success]\n", pmu->name); 355 cleanup: 356 if (mapped) 357 perf_evsel__munmap(evsel); 358 if (opened) 359 perf_evsel__close(evsel); 360 perf_evsel__delete(evsel); 361 362 /* If the affinity was changed, then put it back to all CPUs. */ 363 if (pmu->cpus != NULL) { 364 struct perf_cpu_map *cpus = cpu_map__online(); 365 366 cpu_map__set_affinity(cpus); 367 perf_cpu_map__put(cpus); 368 } 369 set_user_read(pmu, saved_user_read_state); 370 } 371 perf_thread_map__put(threads); 372 return ret; 373 } 374 375 static int test__mmap_user_read_instr(struct test_suite *test __maybe_unused, 376 int subtest __maybe_unused) 377 { 378 return test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS, USER_READ_ENABLED); 379 } 380 381 static int test__mmap_user_read_cycles(struct test_suite *test __maybe_unused, 382 int subtest __maybe_unused) 383 { 384 return test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES, USER_READ_ENABLED); 385 } 386 387 static int test__mmap_user_read_instr_disabled(struct test_suite *test __maybe_unused, 388 int subtest __maybe_unused) 389 { 390 return test_stat_user_read(PERF_COUNT_HW_INSTRUCTIONS, USER_READ_DISABLED); 391 } 392 393 static int test__mmap_user_read_cycles_disabled(struct test_suite *test __maybe_unused, 394 int subtest __maybe_unused) 395 { 396 return test_stat_user_read(PERF_COUNT_HW_CPU_CYCLES, USER_READ_DISABLED); 397 } 398 399 static struct test_case tests__basic_mmap[] = { 400 TEST_CASE_REASON("Read samples using the mmap interface", 401 basic_mmap, 402 "permissions"), 403 TEST_CASE_REASON_EXCLUSIVE("User space counter reading of instructions", 404 mmap_user_read_instr, 405 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \ 406 (defined(__riscv) && __riscv_xlen == 64) 407 "permissions" 408 #else 409 "unsupported" 410 #endif 411 ), 412 TEST_CASE_REASON_EXCLUSIVE("User space counter reading of cycles", 413 mmap_user_read_cycles, 414 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \ 415 (defined(__riscv) && __riscv_xlen == 64) 416 "permissions" 417 #else 418 "unsupported" 419 #endif 420 ), 421 TEST_CASE_REASON_EXCLUSIVE("User space counter disabling instructions", 422 mmap_user_read_instr_disabled, 423 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \ 424 (defined(__riscv) && __riscv_xlen == 64) 425 "permissions" 426 #else 427 "unsupported" 428 #endif 429 ), 430 TEST_CASE_REASON_EXCLUSIVE("User space counter disabling cycles", 431 mmap_user_read_cycles_disabled, 432 #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || \ 433 (defined(__riscv) && __riscv_xlen == 64) 434 "permissions" 435 #else 436 "unsupported" 437 #endif 438 ), 439 { .name = NULL, } 440 }; 441 442 struct test_suite suite__basic_mmap = { 443 .desc = "mmap interface tests", 444 .test_cases = tests__basic_mmap, 445 }; 446