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