1 // SPDX-License-Identifier: GPL-2.0 2 #include "evlist.h" 3 #include "evsel.h" 4 #include "cpumap.h" 5 #include "parse-events.h" 6 #include <errno.h> 7 #include <api/fs/fs.h> 8 #include <subcmd/parse-options.h> 9 #include <perf/cpumap.h> 10 #include "util.h" 11 #include "cloexec.h" 12 #include "record.h" 13 #include "../perf-sys.h" 14 15 typedef void (*setup_probe_fn_t)(struct evsel *evsel); 16 17 static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) 18 { 19 struct evlist *evlist; 20 struct evsel *evsel; 21 unsigned long flags = perf_event_open_cloexec_flag(); 22 int err = -EAGAIN, fd; 23 static pid_t pid = -1; 24 25 evlist = evlist__new(); 26 if (!evlist) 27 return -ENOMEM; 28 29 if (parse_events(evlist, str, NULL)) 30 goto out_delete; 31 32 evsel = perf_evlist__first(evlist); 33 34 while (1) { 35 fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, -1, flags); 36 if (fd < 0) { 37 if (pid == -1 && errno == EACCES) { 38 pid = 0; 39 continue; 40 } 41 goto out_delete; 42 } 43 break; 44 } 45 close(fd); 46 47 fn(evsel); 48 49 fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, -1, flags); 50 if (fd < 0) { 51 if (errno == EINVAL) 52 err = -EINVAL; 53 goto out_delete; 54 } 55 close(fd); 56 err = 0; 57 58 out_delete: 59 evlist__delete(evlist); 60 return err; 61 } 62 63 static bool perf_probe_api(setup_probe_fn_t fn) 64 { 65 const char *try[] = {"cycles:u", "instructions:u", "cpu-clock:u", NULL}; 66 struct perf_cpu_map *cpus; 67 int cpu, ret, i = 0; 68 69 cpus = perf_cpu_map__new(NULL); 70 if (!cpus) 71 return false; 72 cpu = cpus->map[0]; 73 perf_cpu_map__put(cpus); 74 75 do { 76 ret = perf_do_probe_api(fn, cpu, try[i++]); 77 if (!ret) 78 return true; 79 } while (ret == -EAGAIN && try[i]); 80 81 return false; 82 } 83 84 static void perf_probe_sample_identifier(struct evsel *evsel) 85 { 86 evsel->core.attr.sample_type |= PERF_SAMPLE_IDENTIFIER; 87 } 88 89 static void perf_probe_comm_exec(struct evsel *evsel) 90 { 91 evsel->core.attr.comm_exec = 1; 92 } 93 94 static void perf_probe_context_switch(struct evsel *evsel) 95 { 96 evsel->core.attr.context_switch = 1; 97 } 98 99 bool perf_can_sample_identifier(void) 100 { 101 return perf_probe_api(perf_probe_sample_identifier); 102 } 103 104 static bool perf_can_comm_exec(void) 105 { 106 return perf_probe_api(perf_probe_comm_exec); 107 } 108 109 bool perf_can_record_switch_events(void) 110 { 111 return perf_probe_api(perf_probe_context_switch); 112 } 113 114 bool perf_can_record_cpu_wide(void) 115 { 116 struct perf_event_attr attr = { 117 .type = PERF_TYPE_SOFTWARE, 118 .config = PERF_COUNT_SW_CPU_CLOCK, 119 .exclude_kernel = 1, 120 }; 121 struct perf_cpu_map *cpus; 122 int cpu, fd; 123 124 cpus = perf_cpu_map__new(NULL); 125 if (!cpus) 126 return false; 127 cpu = cpus->map[0]; 128 perf_cpu_map__put(cpus); 129 130 fd = sys_perf_event_open(&attr, -1, cpu, -1, 0); 131 if (fd < 0) 132 return false; 133 close(fd); 134 135 return true; 136 } 137 138 void perf_evlist__config(struct evlist *evlist, struct record_opts *opts, 139 struct callchain_param *callchain) 140 { 141 struct evsel *evsel; 142 bool use_sample_identifier = false; 143 bool use_comm_exec; 144 bool sample_id = opts->sample_id; 145 146 /* 147 * Set the evsel leader links before we configure attributes, 148 * since some might depend on this info. 149 */ 150 if (opts->group) 151 perf_evlist__set_leader(evlist); 152 153 if (evlist->core.cpus->map[0] < 0) 154 opts->no_inherit = true; 155 156 use_comm_exec = perf_can_comm_exec(); 157 158 evlist__for_each_entry(evlist, evsel) { 159 perf_evsel__config(evsel, opts, callchain); 160 if (evsel->tracking && use_comm_exec) 161 evsel->core.attr.comm_exec = 1; 162 } 163 164 if (opts->full_auxtrace) { 165 /* 166 * Need to be able to synthesize and parse selected events with 167 * arbitrary sample types, which requires always being able to 168 * match the id. 169 */ 170 use_sample_identifier = perf_can_sample_identifier(); 171 sample_id = true; 172 } else if (evlist->core.nr_entries > 1) { 173 struct evsel *first = perf_evlist__first(evlist); 174 175 evlist__for_each_entry(evlist, evsel) { 176 if (evsel->core.attr.sample_type == first->core.attr.sample_type) 177 continue; 178 use_sample_identifier = perf_can_sample_identifier(); 179 break; 180 } 181 sample_id = true; 182 } 183 184 if (sample_id) { 185 evlist__for_each_entry(evlist, evsel) 186 perf_evsel__set_sample_id(evsel, use_sample_identifier); 187 } 188 189 perf_evlist__set_id_pos(evlist); 190 } 191 192 static int get_max_rate(unsigned int *rate) 193 { 194 return sysctl__read_int("kernel/perf_event_max_sample_rate", (int *)rate); 195 } 196 197 static int record_opts__config_freq(struct record_opts *opts) 198 { 199 bool user_freq = opts->user_freq != UINT_MAX; 200 unsigned int max_rate; 201 202 if (opts->user_interval != ULLONG_MAX) 203 opts->default_interval = opts->user_interval; 204 if (user_freq) 205 opts->freq = opts->user_freq; 206 207 /* 208 * User specified count overrides default frequency. 209 */ 210 if (opts->default_interval) 211 opts->freq = 0; 212 else if (opts->freq) { 213 opts->default_interval = opts->freq; 214 } else { 215 pr_err("frequency and count are zero, aborting\n"); 216 return -1; 217 } 218 219 if (get_max_rate(&max_rate)) 220 return 0; 221 222 /* 223 * User specified frequency is over current maximum. 224 */ 225 if (user_freq && (max_rate < opts->freq)) { 226 if (opts->strict_freq) { 227 pr_err("error: Maximum frequency rate (%'u Hz) exceeded.\n" 228 " Please use -F freq option with a lower value or consider\n" 229 " tweaking /proc/sys/kernel/perf_event_max_sample_rate.\n", 230 max_rate); 231 return -1; 232 } else { 233 pr_warning("warning: Maximum frequency rate (%'u Hz) exceeded, throttling from %'u Hz to %'u Hz.\n" 234 " The limit can be raised via /proc/sys/kernel/perf_event_max_sample_rate.\n" 235 " The kernel will lower it when perf's interrupts take too long.\n" 236 " Use --strict-freq to disable this throttling, refusing to record.\n", 237 max_rate, opts->freq, max_rate); 238 239 opts->freq = max_rate; 240 } 241 } 242 243 /* 244 * Default frequency is over current maximum. 245 */ 246 if (max_rate < opts->freq) { 247 pr_warning("Lowering default frequency rate to %u.\n" 248 "Please consider tweaking " 249 "/proc/sys/kernel/perf_event_max_sample_rate.\n", 250 max_rate); 251 opts->freq = max_rate; 252 } 253 254 return 0; 255 } 256 257 int record_opts__config(struct record_opts *opts) 258 { 259 return record_opts__config_freq(opts); 260 } 261 262 bool perf_evlist__can_select_event(struct evlist *evlist, const char *str) 263 { 264 struct evlist *temp_evlist; 265 struct evsel *evsel; 266 int err, fd, cpu; 267 bool ret = false; 268 pid_t pid = -1; 269 270 temp_evlist = evlist__new(); 271 if (!temp_evlist) 272 return false; 273 274 err = parse_events(temp_evlist, str, NULL); 275 if (err) 276 goto out_delete; 277 278 evsel = perf_evlist__last(temp_evlist); 279 280 if (!evlist || perf_cpu_map__empty(evlist->core.cpus)) { 281 struct perf_cpu_map *cpus = perf_cpu_map__new(NULL); 282 283 cpu = cpus ? cpus->map[0] : 0; 284 perf_cpu_map__put(cpus); 285 } else { 286 cpu = evlist->core.cpus->map[0]; 287 } 288 289 while (1) { 290 fd = sys_perf_event_open(&evsel->core.attr, pid, cpu, -1, 291 perf_event_open_cloexec_flag()); 292 if (fd < 0) { 293 if (pid == -1 && errno == EACCES) { 294 pid = 0; 295 continue; 296 } 297 goto out_delete; 298 } 299 break; 300 } 301 close(fd); 302 ret = true; 303 304 out_delete: 305 evlist__delete(temp_evlist); 306 return ret; 307 } 308 309 int record__parse_freq(const struct option *opt, const char *str, int unset __maybe_unused) 310 { 311 unsigned int freq; 312 struct record_opts *opts = opt->value; 313 314 if (!str) 315 return -EINVAL; 316 317 if (strcasecmp(str, "max") == 0) { 318 if (get_max_rate(&freq)) { 319 pr_err("couldn't read /proc/sys/kernel/perf_event_max_sample_rate\n"); 320 return -1; 321 } 322 pr_info("info: Using a maximum frequency rate of %'d Hz\n", freq); 323 } else { 324 freq = atoi(str); 325 } 326 327 opts->user_freq = freq; 328 return 0; 329 } 330