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