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