1 #include "evlist.h" 2 #include "evsel.h" 3 #include "cpumap.h" 4 #include "parse-events.h" 5 #include "fs.h" 6 #include "util.h" 7 8 typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel); 9 10 static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str) 11 { 12 struct perf_evlist *evlist; 13 struct perf_evsel *evsel; 14 int err = -EAGAIN, fd; 15 16 evlist = perf_evlist__new(); 17 if (!evlist) 18 return -ENOMEM; 19 20 if (parse_events(evlist, str)) 21 goto out_delete; 22 23 evsel = perf_evlist__first(evlist); 24 25 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 26 if (fd < 0) 27 goto out_delete; 28 close(fd); 29 30 fn(evsel); 31 32 fd = sys_perf_event_open(&evsel->attr, -1, cpu, -1, 0); 33 if (fd < 0) { 34 if (errno == EINVAL) 35 err = -EINVAL; 36 goto out_delete; 37 } 38 close(fd); 39 err = 0; 40 41 out_delete: 42 perf_evlist__delete(evlist); 43 return err; 44 } 45 46 static bool perf_probe_api(setup_probe_fn_t fn) 47 { 48 const char *try[] = {"cycles:u", "instructions:u", "cpu-clock", NULL}; 49 struct cpu_map *cpus; 50 int cpu, ret, i = 0; 51 52 cpus = cpu_map__new(NULL); 53 if (!cpus) 54 return false; 55 cpu = cpus->map[0]; 56 cpu_map__delete(cpus); 57 58 do { 59 ret = perf_do_probe_api(fn, cpu, try[i++]); 60 if (!ret) 61 return true; 62 } while (ret == -EAGAIN && try[i]); 63 64 return false; 65 } 66 67 static void perf_probe_sample_identifier(struct perf_evsel *evsel) 68 { 69 evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER; 70 } 71 72 bool perf_can_sample_identifier(void) 73 { 74 return perf_probe_api(perf_probe_sample_identifier); 75 } 76 77 void perf_evlist__config(struct perf_evlist *evlist, 78 struct perf_record_opts *opts) 79 { 80 struct perf_evsel *evsel; 81 bool use_sample_identifier = false; 82 83 /* 84 * Set the evsel leader links before we configure attributes, 85 * since some might depend on this info. 86 */ 87 if (opts->group) 88 perf_evlist__set_leader(evlist); 89 90 if (evlist->cpus->map[0] < 0) 91 opts->no_inherit = true; 92 93 list_for_each_entry(evsel, &evlist->entries, node) 94 perf_evsel__config(evsel, opts); 95 96 if (evlist->nr_entries > 1) { 97 struct perf_evsel *first = perf_evlist__first(evlist); 98 99 list_for_each_entry(evsel, &evlist->entries, node) { 100 if (evsel->attr.sample_type == first->attr.sample_type) 101 continue; 102 use_sample_identifier = perf_can_sample_identifier(); 103 break; 104 } 105 list_for_each_entry(evsel, &evlist->entries, node) 106 perf_evsel__set_sample_id(evsel, use_sample_identifier); 107 } 108 109 perf_evlist__set_id_pos(evlist); 110 } 111 112 static int get_max_rate(unsigned int *rate) 113 { 114 char path[PATH_MAX]; 115 const char *procfs = procfs__mountpoint(); 116 117 if (!procfs) 118 return -1; 119 120 snprintf(path, PATH_MAX, 121 "%s/sys/kernel/perf_event_max_sample_rate", procfs); 122 123 return filename__read_int(path, (int *) rate); 124 } 125 126 static int perf_record_opts__config_freq(struct perf_record_opts *opts) 127 { 128 bool user_freq = opts->user_freq != UINT_MAX; 129 unsigned int max_rate; 130 131 if (opts->user_interval != ULLONG_MAX) 132 opts->default_interval = opts->user_interval; 133 if (user_freq) 134 opts->freq = opts->user_freq; 135 136 /* 137 * User specified count overrides default frequency. 138 */ 139 if (opts->default_interval) 140 opts->freq = 0; 141 else if (opts->freq) { 142 opts->default_interval = opts->freq; 143 } else { 144 pr_err("frequency and count are zero, aborting\n"); 145 return -1; 146 } 147 148 if (get_max_rate(&max_rate)) 149 return 0; 150 151 /* 152 * User specified frequency is over current maximum. 153 */ 154 if (user_freq && (max_rate < opts->freq)) { 155 pr_err("Maximum frequency rate (%u) reached.\n" 156 "Please use -F freq option with lower value or consider\n" 157 "tweaking /proc/sys/kernel/perf_event_max_sample_rate.\n", 158 max_rate); 159 return -1; 160 } 161 162 /* 163 * Default frequency is over current maximum. 164 */ 165 if (max_rate < opts->freq) { 166 pr_warning("Lowering default frequency rate to %u.\n" 167 "Please consider tweaking " 168 "/proc/sys/kernel/perf_event_max_sample_rate.\n", 169 max_rate); 170 opts->freq = max_rate; 171 } 172 173 return 0; 174 } 175 176 int perf_record_opts__config(struct perf_record_opts *opts) 177 { 178 return perf_record_opts__config_freq(opts); 179 } 180