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