1faf96706SAdrian Hunter #include "evlist.h" 2faf96706SAdrian Hunter #include "evsel.h" 3faf96706SAdrian Hunter #include "cpumap.h" 475562573SAdrian Hunter #include "parse-events.h" 5cd0cfad7SBorislav Petkov #include <api/fs/fs.h> 6714647bdSJiri Olsa #include "util.h" 757480d2cSYann Droneaud #include "cloexec.h" 875562573SAdrian Hunter 975562573SAdrian Hunter typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel); 1075562573SAdrian Hunter 1175562573SAdrian Hunter static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) 1275562573SAdrian Hunter { 1375562573SAdrian Hunter struct perf_evlist *evlist; 1475562573SAdrian Hunter struct perf_evsel *evsel; 1557480d2cSYann Droneaud unsigned long flags = perf_event_open_cloexec_flag(); 1675562573SAdrian Hunter int err = -EAGAIN, fd; 1746ec69adSAdrian Hunter static pid_t pid = -1; 1875562573SAdrian Hunter 1975562573SAdrian Hunter evlist = perf_evlist__new(); 2075562573SAdrian Hunter if (!evlist) 2175562573SAdrian Hunter return -ENOMEM; 2275562573SAdrian Hunter 23b39b8393SJiri Olsa if (parse_events(evlist, str, NULL)) 2475562573SAdrian Hunter goto out_delete; 2575562573SAdrian Hunter 2675562573SAdrian Hunter evsel = perf_evlist__first(evlist); 2775562573SAdrian Hunter 2846ec69adSAdrian Hunter while (1) { 2946ec69adSAdrian Hunter fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags); 3046ec69adSAdrian Hunter if (fd < 0) { 3146ec69adSAdrian Hunter if (pid == -1 && errno == EACCES) { 3246ec69adSAdrian Hunter pid = 0; 3346ec69adSAdrian Hunter continue; 3446ec69adSAdrian Hunter } 3575562573SAdrian Hunter goto out_delete; 3646ec69adSAdrian Hunter } 3746ec69adSAdrian Hunter break; 3846ec69adSAdrian Hunter } 3975562573SAdrian Hunter close(fd); 4075562573SAdrian Hunter 4175562573SAdrian Hunter fn(evsel); 4275562573SAdrian Hunter 4346ec69adSAdrian Hunter fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags); 4475562573SAdrian Hunter if (fd < 0) { 4575562573SAdrian Hunter if (errno == EINVAL) 4675562573SAdrian Hunter err = -EINVAL; 4775562573SAdrian Hunter goto out_delete; 4875562573SAdrian Hunter } 4975562573SAdrian Hunter close(fd); 5075562573SAdrian Hunter err = 0; 5175562573SAdrian Hunter 5275562573SAdrian Hunter out_delete: 5375562573SAdrian Hunter perf_evlist__delete(evlist); 5475562573SAdrian Hunter return err; 5575562573SAdrian Hunter } 5675562573SAdrian Hunter 5775562573SAdrian Hunter static bool perf_probe_api(setup_probe_fn_t fn) 5875562573SAdrian Hunter { 59c6fa3565SAdrian Hunter const char *try[] = {"cycles:u", "instructions:u", "cpu-clock:u", NULL}; 6075562573SAdrian Hunter struct cpu_map *cpus; 6175562573SAdrian Hunter int cpu, ret, i = 0; 6275562573SAdrian Hunter 6375562573SAdrian Hunter cpus = cpu_map__new(NULL); 6475562573SAdrian Hunter if (!cpus) 6575562573SAdrian Hunter return false; 6675562573SAdrian Hunter cpu = cpus->map[0]; 67f30a79b0SJiri Olsa cpu_map__put(cpus); 6875562573SAdrian Hunter 6975562573SAdrian Hunter do { 7075562573SAdrian Hunter ret = perf_do_probe_api(fn, cpu, try[i++]); 7175562573SAdrian Hunter if (!ret) 7275562573SAdrian Hunter return true; 7375562573SAdrian Hunter } while (ret == -EAGAIN && try[i]); 7475562573SAdrian Hunter 7575562573SAdrian Hunter return false; 7675562573SAdrian Hunter } 7775562573SAdrian Hunter 7875562573SAdrian Hunter static void perf_probe_sample_identifier(struct perf_evsel *evsel) 7975562573SAdrian Hunter { 8075562573SAdrian Hunter evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER; 8175562573SAdrian Hunter } 8275562573SAdrian Hunter 8339e09d40SAdrian Hunter static void perf_probe_comm_exec(struct perf_evsel *evsel) 8439e09d40SAdrian Hunter { 8539e09d40SAdrian Hunter evsel->attr.comm_exec = 1; 8639e09d40SAdrian Hunter } 8739e09d40SAdrian Hunter 88b757bb09SAdrian Hunter static void perf_probe_context_switch(struct perf_evsel *evsel) 89b757bb09SAdrian Hunter { 90b757bb09SAdrian Hunter evsel->attr.context_switch = 1; 91b757bb09SAdrian Hunter } 92b757bb09SAdrian Hunter 9375562573SAdrian Hunter bool perf_can_sample_identifier(void) 9475562573SAdrian Hunter { 9575562573SAdrian Hunter return perf_probe_api(perf_probe_sample_identifier); 9675562573SAdrian Hunter } 97faf96706SAdrian Hunter 9839e09d40SAdrian Hunter static bool perf_can_comm_exec(void) 9939e09d40SAdrian Hunter { 10039e09d40SAdrian Hunter return perf_probe_api(perf_probe_comm_exec); 10139e09d40SAdrian Hunter } 10239e09d40SAdrian Hunter 103b757bb09SAdrian Hunter bool perf_can_record_switch_events(void) 104b757bb09SAdrian Hunter { 105b757bb09SAdrian Hunter return perf_probe_api(perf_probe_context_switch); 106b757bb09SAdrian Hunter } 107b757bb09SAdrian Hunter 10883509565SAdrian Hunter bool perf_can_record_cpu_wide(void) 10983509565SAdrian Hunter { 11083509565SAdrian Hunter struct perf_event_attr attr = { 11183509565SAdrian Hunter .type = PERF_TYPE_SOFTWARE, 11283509565SAdrian Hunter .config = PERF_COUNT_SW_CPU_CLOCK, 11383509565SAdrian Hunter .exclude_kernel = 1, 11483509565SAdrian Hunter }; 11583509565SAdrian Hunter struct cpu_map *cpus; 11683509565SAdrian Hunter int cpu, fd; 11783509565SAdrian Hunter 11883509565SAdrian Hunter cpus = cpu_map__new(NULL); 11983509565SAdrian Hunter if (!cpus) 12083509565SAdrian Hunter return false; 12183509565SAdrian Hunter cpu = cpus->map[0]; 12283509565SAdrian Hunter cpu_map__put(cpus); 12383509565SAdrian Hunter 12483509565SAdrian Hunter fd = sys_perf_event_open(&attr, -1, cpu, -1, 0); 12583509565SAdrian Hunter if (fd < 0) 12683509565SAdrian Hunter return false; 12783509565SAdrian Hunter close(fd); 12883509565SAdrian Hunter 12983509565SAdrian Hunter return true; 13083509565SAdrian Hunter } 13183509565SAdrian Hunter 132e68ae9cfSArnaldo Carvalho de Melo void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts, 133e68ae9cfSArnaldo Carvalho de Melo struct callchain_param *callchain) 134faf96706SAdrian Hunter { 135faf96706SAdrian Hunter struct perf_evsel *evsel; 13675562573SAdrian Hunter bool use_sample_identifier = false; 13739e09d40SAdrian Hunter bool use_comm_exec; 13875562573SAdrian Hunter 139faf96706SAdrian Hunter /* 140faf96706SAdrian Hunter * Set the evsel leader links before we configure attributes, 141faf96706SAdrian Hunter * since some might depend on this info. 142faf96706SAdrian Hunter */ 143faf96706SAdrian Hunter if (opts->group) 144faf96706SAdrian Hunter perf_evlist__set_leader(evlist); 145faf96706SAdrian Hunter 146faf96706SAdrian Hunter if (evlist->cpus->map[0] < 0) 147faf96706SAdrian Hunter opts->no_inherit = true; 148faf96706SAdrian Hunter 14939e09d40SAdrian Hunter use_comm_exec = perf_can_comm_exec(); 15039e09d40SAdrian Hunter 151*e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) { 152e68ae9cfSArnaldo Carvalho de Melo perf_evsel__config(evsel, opts, callchain); 15360b0896cSAdrian Hunter if (evsel->tracking && use_comm_exec) 15439e09d40SAdrian Hunter evsel->attr.comm_exec = 1; 15539e09d40SAdrian Hunter } 156faf96706SAdrian Hunter 1579e0cc4feSAdrian Hunter if (opts->full_auxtrace) { 1589e0cc4feSAdrian Hunter /* 1599e0cc4feSAdrian Hunter * Need to be able to synthesize and parse selected events with 1609e0cc4feSAdrian Hunter * arbitrary sample types, which requires always being able to 1619e0cc4feSAdrian Hunter * match the id. 1629e0cc4feSAdrian Hunter */ 1639e0cc4feSAdrian Hunter use_sample_identifier = perf_can_sample_identifier(); 164*e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) 1659e0cc4feSAdrian Hunter perf_evsel__set_sample_id(evsel, use_sample_identifier); 1669e0cc4feSAdrian Hunter } else if (evlist->nr_entries > 1) { 16775562573SAdrian Hunter struct perf_evsel *first = perf_evlist__first(evlist); 16875562573SAdrian Hunter 169*e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) { 17075562573SAdrian Hunter if (evsel->attr.sample_type == first->attr.sample_type) 17175562573SAdrian Hunter continue; 17275562573SAdrian Hunter use_sample_identifier = perf_can_sample_identifier(); 17375562573SAdrian Hunter break; 174faf96706SAdrian Hunter } 175*e5cadb93SArnaldo Carvalho de Melo evlist__for_each_entry(evlist, evsel) 17675562573SAdrian Hunter perf_evsel__set_sample_id(evsel, use_sample_identifier); 17775562573SAdrian Hunter } 17875562573SAdrian Hunter 17975562573SAdrian Hunter perf_evlist__set_id_pos(evlist); 180faf96706SAdrian Hunter } 181714647bdSJiri Olsa 182714647bdSJiri Olsa static int get_max_rate(unsigned int *rate) 183714647bdSJiri Olsa { 184ce27309fSArnaldo Carvalho de Melo return sysctl__read_int("kernel/perf_event_max_sample_rate", (int *)rate); 185714647bdSJiri Olsa } 186714647bdSJiri Olsa 187b4006796SArnaldo Carvalho de Melo static int record_opts__config_freq(struct record_opts *opts) 188714647bdSJiri Olsa { 189714647bdSJiri Olsa bool user_freq = opts->user_freq != UINT_MAX; 190714647bdSJiri Olsa unsigned int max_rate; 191714647bdSJiri Olsa 192714647bdSJiri Olsa if (opts->user_interval != ULLONG_MAX) 193714647bdSJiri Olsa opts->default_interval = opts->user_interval; 194714647bdSJiri Olsa if (user_freq) 195714647bdSJiri Olsa opts->freq = opts->user_freq; 196714647bdSJiri Olsa 197714647bdSJiri Olsa /* 198714647bdSJiri Olsa * User specified count overrides default frequency. 199714647bdSJiri Olsa */ 200714647bdSJiri Olsa if (opts->default_interval) 201714647bdSJiri Olsa opts->freq = 0; 202714647bdSJiri Olsa else if (opts->freq) { 203714647bdSJiri Olsa opts->default_interval = opts->freq; 204714647bdSJiri Olsa } else { 205714647bdSJiri Olsa pr_err("frequency and count are zero, aborting\n"); 206714647bdSJiri Olsa return -1; 207714647bdSJiri Olsa } 208714647bdSJiri Olsa 209714647bdSJiri Olsa if (get_max_rate(&max_rate)) 210714647bdSJiri Olsa return 0; 211714647bdSJiri Olsa 212714647bdSJiri Olsa /* 213714647bdSJiri Olsa * User specified frequency is over current maximum. 214714647bdSJiri Olsa */ 215714647bdSJiri Olsa if (user_freq && (max_rate < opts->freq)) { 216714647bdSJiri Olsa pr_err("Maximum frequency rate (%u) reached.\n" 217714647bdSJiri Olsa "Please use -F freq option with lower value or consider\n" 218714647bdSJiri Olsa "tweaking /proc/sys/kernel/perf_event_max_sample_rate.\n", 219714647bdSJiri Olsa max_rate); 220714647bdSJiri Olsa return -1; 221714647bdSJiri Olsa } 222714647bdSJiri Olsa 223714647bdSJiri Olsa /* 224714647bdSJiri Olsa * Default frequency is over current maximum. 225714647bdSJiri Olsa */ 226714647bdSJiri Olsa if (max_rate < opts->freq) { 227714647bdSJiri Olsa pr_warning("Lowering default frequency rate to %u.\n" 228714647bdSJiri Olsa "Please consider tweaking " 229714647bdSJiri Olsa "/proc/sys/kernel/perf_event_max_sample_rate.\n", 230714647bdSJiri Olsa max_rate); 231714647bdSJiri Olsa opts->freq = max_rate; 232714647bdSJiri Olsa } 233714647bdSJiri Olsa 234714647bdSJiri Olsa return 0; 235714647bdSJiri Olsa } 236714647bdSJiri Olsa 237b4006796SArnaldo Carvalho de Melo int record_opts__config(struct record_opts *opts) 238714647bdSJiri Olsa { 239b4006796SArnaldo Carvalho de Melo return record_opts__config_freq(opts); 240714647bdSJiri Olsa } 241c09ec622SAdrian Hunter 242c09ec622SAdrian Hunter bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str) 243c09ec622SAdrian Hunter { 244c09ec622SAdrian Hunter struct perf_evlist *temp_evlist; 245c09ec622SAdrian Hunter struct perf_evsel *evsel; 246c09ec622SAdrian Hunter int err, fd, cpu; 247c09ec622SAdrian Hunter bool ret = false; 24846ec69adSAdrian Hunter pid_t pid = -1; 249c09ec622SAdrian Hunter 250c09ec622SAdrian Hunter temp_evlist = perf_evlist__new(); 251c09ec622SAdrian Hunter if (!temp_evlist) 252c09ec622SAdrian Hunter return false; 253c09ec622SAdrian Hunter 254b39b8393SJiri Olsa err = parse_events(temp_evlist, str, NULL); 255c09ec622SAdrian Hunter if (err) 256c09ec622SAdrian Hunter goto out_delete; 257c09ec622SAdrian Hunter 258c09ec622SAdrian Hunter evsel = perf_evlist__last(temp_evlist); 259c09ec622SAdrian Hunter 260c09ec622SAdrian Hunter if (!evlist || cpu_map__empty(evlist->cpus)) { 261c09ec622SAdrian Hunter struct cpu_map *cpus = cpu_map__new(NULL); 262c09ec622SAdrian Hunter 263c09ec622SAdrian Hunter cpu = cpus ? cpus->map[0] : 0; 264f30a79b0SJiri Olsa cpu_map__put(cpus); 265c09ec622SAdrian Hunter } else { 266c09ec622SAdrian Hunter cpu = evlist->cpus->map[0]; 267c09ec622SAdrian Hunter } 268c09ec622SAdrian Hunter 26946ec69adSAdrian Hunter while (1) { 27046ec69adSAdrian Hunter fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, 27157480d2cSYann Droneaud perf_event_open_cloexec_flag()); 27246ec69adSAdrian Hunter if (fd < 0) { 27346ec69adSAdrian Hunter if (pid == -1 && errno == EACCES) { 27446ec69adSAdrian Hunter pid = 0; 27546ec69adSAdrian Hunter continue; 27646ec69adSAdrian Hunter } 27746ec69adSAdrian Hunter goto out_delete; 27846ec69adSAdrian Hunter } 27946ec69adSAdrian Hunter break; 28046ec69adSAdrian Hunter } 281c09ec622SAdrian Hunter close(fd); 282c09ec622SAdrian Hunter ret = true; 283c09ec622SAdrian Hunter 284c09ec622SAdrian Hunter out_delete: 285c09ec622SAdrian Hunter perf_evlist__delete(temp_evlist); 286c09ec622SAdrian Hunter return ret; 287c09ec622SAdrian Hunter } 288