1 /* SPDX-License-Identifier: GPL-2.0 */ 2 3 #include "perf-sys.h" 4 #include "util/cloexec.h" 5 #include "util/evlist.h" 6 #include "util/evsel.h" 7 #include "util/parse-events.h" 8 #include "util/perf_api_probe.h" 9 #include <perf/cpumap.h> 10 #include <errno.h> 11 12 typedef void (*setup_probe_fn_t)(struct evsel *evsel); 13 14 static int perf_do_probe_api(setup_probe_fn_t fn, struct perf_cpu cpu, const char *str) 15 { 16 struct evlist *evlist; 17 struct evsel *evsel; 18 unsigned long flags = perf_event_open_cloexec_flag(); 19 int err = -EAGAIN, fd; 20 static pid_t pid = -1; 21 22 evlist = evlist__new(); 23 if (!evlist) 24 return -ENOMEM; 25 26 if (parse_event(evlist, str)) 27 goto out_delete; 28 29 evsel = evlist__first(evlist); 30 31 while (1) { 32 fd = sys_perf_event_open(&evsel->core.attr, pid, cpu.cpu, -1, flags); 33 if (fd < 0) { 34 if (pid == -1 && errno == EACCES) { 35 pid = 0; 36 continue; 37 } 38 goto out_delete; 39 } 40 break; 41 } 42 close(fd); 43 44 fn(evsel); 45 46 fd = sys_perf_event_open(&evsel->core.attr, pid, cpu.cpu, -1, flags); 47 if (fd < 0) { 48 if (errno == EINVAL) 49 err = -EINVAL; 50 goto out_delete; 51 } 52 close(fd); 53 err = 0; 54 55 out_delete: 56 evlist__delete(evlist); 57 return err; 58 } 59 60 static bool perf_probe_api(setup_probe_fn_t fn) 61 { 62 struct perf_pmu *pmu; 63 struct perf_cpu_map *cpus; 64 struct perf_cpu cpu; 65 int ret = 0; 66 67 cpus = perf_cpu_map__new_online_cpus(); 68 if (!cpus) 69 return false; 70 cpu = perf_cpu_map__cpu(cpus, 0); 71 perf_cpu_map__put(cpus); 72 73 ret = perf_do_probe_api(fn, cpu, "software/cpu-clock/u"); 74 if (!ret) 75 return true; 76 77 pmu = perf_pmus__scan_core(/*pmu=*/NULL); 78 if (pmu) { 79 const char *try[] = {"cycles", "instructions", NULL}; 80 char buf[256]; 81 int i = 0; 82 83 while (ret == -EAGAIN && try[i]) { 84 snprintf(buf, sizeof(buf), "%s/%s/u", pmu->name, try[i++]); 85 ret = perf_do_probe_api(fn, cpu, buf); 86 if (!ret) 87 return true; 88 } 89 } 90 return false; 91 } 92 93 static void perf_probe_sample_identifier(struct evsel *evsel) 94 { 95 evsel->core.attr.sample_type |= PERF_SAMPLE_IDENTIFIER; 96 } 97 98 static void perf_probe_comm_exec(struct evsel *evsel) 99 { 100 evsel->core.attr.comm_exec = 1; 101 } 102 103 static void perf_probe_context_switch(struct evsel *evsel) 104 { 105 evsel->core.attr.context_switch = 1; 106 } 107 108 static void perf_probe_text_poke(struct evsel *evsel) 109 { 110 evsel->core.attr.text_poke = 1; 111 } 112 113 static void perf_probe_build_id(struct evsel *evsel) 114 { 115 evsel->core.attr.build_id = 1; 116 } 117 118 static void perf_probe_cgroup(struct evsel *evsel) 119 { 120 evsel->core.attr.cgroup = 1; 121 } 122 123 bool perf_can_sample_identifier(void) 124 { 125 return perf_probe_api(perf_probe_sample_identifier); 126 } 127 128 bool perf_can_comm_exec(void) 129 { 130 return perf_probe_api(perf_probe_comm_exec); 131 } 132 133 bool perf_can_record_switch_events(void) 134 { 135 return perf_probe_api(perf_probe_context_switch); 136 } 137 138 bool perf_can_record_text_poke_events(void) 139 { 140 return perf_probe_api(perf_probe_text_poke); 141 } 142 143 bool perf_can_record_cpu_wide(void) 144 { 145 struct perf_event_attr attr = { 146 .type = PERF_TYPE_SOFTWARE, 147 .config = PERF_COUNT_SW_CPU_CLOCK, 148 .exclude_kernel = 1, 149 }; 150 struct perf_cpu_map *cpus; 151 struct perf_cpu cpu; 152 int fd; 153 154 cpus = perf_cpu_map__new_online_cpus(); 155 if (!cpus) 156 return false; 157 158 cpu = perf_cpu_map__cpu(cpus, 0); 159 perf_cpu_map__put(cpus); 160 161 fd = sys_perf_event_open(&attr, -1, cpu.cpu, -1, 0); 162 if (fd < 0) 163 return false; 164 close(fd); 165 166 return true; 167 } 168 169 /* 170 * Architectures are expected to know if AUX area sampling is supported by the 171 * hardware. Here we check for kernel support. 172 */ 173 bool perf_can_aux_sample(void) 174 { 175 struct perf_event_attr attr = { 176 .size = sizeof(struct perf_event_attr), 177 .exclude_kernel = 1, 178 /* 179 * Non-zero value causes the kernel to calculate the effective 180 * attribute size up to that byte. 181 */ 182 .aux_sample_size = 1, 183 }; 184 int fd; 185 186 fd = sys_perf_event_open(&attr, -1, 0, -1, 0); 187 /* 188 * If the kernel attribute is big enough to contain aux_sample_size 189 * then we assume that it is supported. We are relying on the kernel to 190 * validate the attribute size before anything else that could be wrong. 191 */ 192 if (fd < 0 && errno == E2BIG) 193 return false; 194 if (fd >= 0) 195 close(fd); 196 197 return true; 198 } 199 200 bool perf_can_record_build_id(void) 201 { 202 return perf_probe_api(perf_probe_build_id); 203 } 204 205 bool perf_can_record_cgroup(void) 206 { 207 return perf_probe_api(perf_probe_cgroup); 208 } 209