1 // SPDX-License-Identifier: GPL-2.0 2 #include <errno.h> 3 #include <inttypes.h> 4 /* For the CLR_() macros */ 5 #include <pthread.h> 6 #include <perf/cpumap.h> 7 8 #include "debug.h" 9 #include "evlist.h" 10 #include "evsel.h" 11 #include "thread_map.h" 12 #include "cpumap.h" 13 #include "tests.h" 14 #include <linux/err.h> 15 #include <linux/kernel.h> 16 #include <linux/string.h> 17 #include <perf/evlist.h> 18 19 /* 20 * This test will generate random numbers of calls to some getpid syscalls, 21 * then establish an mmap for a group of events that are created to monitor 22 * the syscalls. 23 * 24 * It will receive the events, using mmap, use its PERF_SAMPLE_ID generated 25 * sample.id field to map back to its respective perf_evsel instance. 26 * 27 * Then it checks if the number of syscalls reported as perf events by 28 * the kernel corresponds to the number of syscalls made. 29 */ 30 int test__basic_mmap(struct test *test __maybe_unused, int subtest __maybe_unused) 31 { 32 int err = -1; 33 union perf_event *event; 34 struct perf_thread_map *threads; 35 struct perf_cpu_map *cpus; 36 struct evlist *evlist; 37 cpu_set_t cpu_set; 38 const char *syscall_names[] = { "getsid", "getppid", "getpgid", }; 39 pid_t (*syscalls[])(void) = { (void *)getsid, getppid, (void*)getpgid }; 40 #define nsyscalls ARRAY_SIZE(syscall_names) 41 unsigned int nr_events[nsyscalls], 42 expected_nr_events[nsyscalls], i, j; 43 struct evsel *evsels[nsyscalls], *evsel; 44 char sbuf[STRERR_BUFSIZE]; 45 struct perf_mmap *md; 46 47 threads = thread_map__new(-1, getpid(), UINT_MAX); 48 if (threads == NULL) { 49 pr_debug("thread_map__new\n"); 50 return -1; 51 } 52 53 cpus = perf_cpu_map__new(NULL); 54 if (cpus == NULL) { 55 pr_debug("cpu_map__new\n"); 56 goto out_free_threads; 57 } 58 59 CPU_ZERO(&cpu_set); 60 CPU_SET(cpus->map[0], &cpu_set); 61 sched_setaffinity(0, sizeof(cpu_set), &cpu_set); 62 if (sched_setaffinity(0, sizeof(cpu_set), &cpu_set) < 0) { 63 pr_debug("sched_setaffinity() failed on CPU %d: %s ", 64 cpus->map[0], str_error_r(errno, sbuf, sizeof(sbuf))); 65 goto out_free_cpus; 66 } 67 68 evlist = evlist__new(); 69 if (evlist == NULL) { 70 pr_debug("perf_evlist__new\n"); 71 goto out_free_cpus; 72 } 73 74 perf_evlist__set_maps(&evlist->core, cpus, threads); 75 76 for (i = 0; i < nsyscalls; ++i) { 77 char name[64]; 78 79 snprintf(name, sizeof(name), "sys_enter_%s", syscall_names[i]); 80 evsels[i] = perf_evsel__newtp("syscalls", name); 81 if (IS_ERR(evsels[i])) { 82 pr_debug("perf_evsel__new(%s)\n", name); 83 goto out_delete_evlist; 84 } 85 86 evsels[i]->core.attr.wakeup_events = 1; 87 perf_evsel__set_sample_id(evsels[i], false); 88 89 evlist__add(evlist, evsels[i]); 90 91 if (evsel__open(evsels[i], cpus, threads) < 0) { 92 pr_debug("failed to open counter: %s, " 93 "tweak /proc/sys/kernel/perf_event_paranoid?\n", 94 str_error_r(errno, sbuf, sizeof(sbuf))); 95 goto out_delete_evlist; 96 } 97 98 nr_events[i] = 0; 99 expected_nr_events[i] = 1 + rand() % 127; 100 } 101 102 if (perf_evlist__mmap(evlist, 128) < 0) { 103 pr_debug("failed to mmap events: %d (%s)\n", errno, 104 str_error_r(errno, sbuf, sizeof(sbuf))); 105 goto out_delete_evlist; 106 } 107 108 for (i = 0; i < nsyscalls; ++i) 109 for (j = 0; j < expected_nr_events[i]; ++j) { 110 int foo = syscalls[i](); 111 ++foo; 112 } 113 114 md = &evlist->mmap[0]; 115 if (perf_mmap__read_init(md) < 0) 116 goto out_init; 117 118 while ((event = perf_mmap__read_event(md)) != NULL) { 119 struct perf_sample sample; 120 121 if (event->header.type != PERF_RECORD_SAMPLE) { 122 pr_debug("unexpected %s event\n", 123 perf_event__name(event->header.type)); 124 goto out_delete_evlist; 125 } 126 127 err = perf_evlist__parse_sample(evlist, event, &sample); 128 if (err) { 129 pr_err("Can't parse sample, err = %d\n", err); 130 goto out_delete_evlist; 131 } 132 133 err = -1; 134 evsel = perf_evlist__id2evsel(evlist, sample.id); 135 if (evsel == NULL) { 136 pr_debug("event with id %" PRIu64 137 " doesn't map to an evsel\n", sample.id); 138 goto out_delete_evlist; 139 } 140 nr_events[evsel->idx]++; 141 perf_mmap__consume(md); 142 } 143 perf_mmap__read_done(md); 144 145 out_init: 146 err = 0; 147 evlist__for_each_entry(evlist, evsel) { 148 if (nr_events[evsel->idx] != expected_nr_events[evsel->idx]) { 149 pr_debug("expected %d %s events, got %d\n", 150 expected_nr_events[evsel->idx], 151 perf_evsel__name(evsel), nr_events[evsel->idx]); 152 err = -1; 153 goto out_delete_evlist; 154 } 155 } 156 157 out_delete_evlist: 158 evlist__delete(evlist); 159 cpus = NULL; 160 threads = NULL; 161 out_free_cpus: 162 perf_cpu_map__put(cpus); 163 out_free_threads: 164 perf_thread_map__put(threads); 165 return err; 166 } 167