Blame view

tools/perf/util/record.c 6.04 KB
faf967068   Adrian Hunter   perf evlist: Move...
1
2
3
  #include "evlist.h"
  #include "evsel.h"
  #include "cpumap.h"
75562573b   Adrian Hunter   perf tools: Add s...
4
  #include "parse-events.h"
a43783aee   Arnaldo Carvalho de Melo   perf tools: Inclu...
5
  #include <errno.h>
cd0cfad74   Borislav Petkov   perf tools: Move ...
6
  #include <api/fs/fs.h>
714647bdc   Jiri Olsa   perf tools: Check...
7
  #include "util.h"
57480d2cd   Yann Droneaud   perf tools: Enabl...
8
  #include "cloexec.h"
75562573b   Adrian Hunter   perf tools: Add s...
9
10
11
12
13
14
15
  
  typedef void (*setup_probe_fn_t)(struct perf_evsel *evsel);
  
  static int perf_do_probe_api(setup_probe_fn_t fn, int cpu, const char *str)
  {
  	struct perf_evlist *evlist;
  	struct perf_evsel *evsel;
57480d2cd   Yann Droneaud   perf tools: Enabl...
16
  	unsigned long flags = perf_event_open_cloexec_flag();
75562573b   Adrian Hunter   perf tools: Add s...
17
  	int err = -EAGAIN, fd;
46ec69add   Adrian Hunter   perf tools: Fix p...
18
  	static pid_t pid = -1;
75562573b   Adrian Hunter   perf tools: Add s...
19
20
21
22
  
  	evlist = perf_evlist__new();
  	if (!evlist)
  		return -ENOMEM;
b39b83930   Jiri Olsa   perf tools: Add p...
23
  	if (parse_events(evlist, str, NULL))
75562573b   Adrian Hunter   perf tools: Add s...
24
25
26
  		goto out_delete;
  
  	evsel = perf_evlist__first(evlist);
46ec69add   Adrian Hunter   perf tools: Fix p...
27
28
29
30
31
32
33
34
35
36
37
  	while (1) {
  		fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags);
  		if (fd < 0) {
  			if (pid == -1 && errno == EACCES) {
  				pid = 0;
  				continue;
  			}
  			goto out_delete;
  		}
  		break;
  	}
75562573b   Adrian Hunter   perf tools: Add s...
38
39
40
  	close(fd);
  
  	fn(evsel);
46ec69add   Adrian Hunter   perf tools: Fix p...
41
  	fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1, flags);
75562573b   Adrian Hunter   perf tools: Add s...
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
  	if (fd < 0) {
  		if (errno == EINVAL)
  			err = -EINVAL;
  		goto out_delete;
  	}
  	close(fd);
  	err = 0;
  
  out_delete:
  	perf_evlist__delete(evlist);
  	return err;
  }
  
  static bool perf_probe_api(setup_probe_fn_t fn)
  {
c6fa35659   Adrian Hunter   perf tools: Fix o...
57
  	const char *try[] = {"cycles:u", "instructions:u", "cpu-clock:u", NULL};
75562573b   Adrian Hunter   perf tools: Add s...
58
59
60
61
62
63
64
  	struct cpu_map *cpus;
  	int cpu, ret, i = 0;
  
  	cpus = cpu_map__new(NULL);
  	if (!cpus)
  		return false;
  	cpu = cpus->map[0];
f30a79b01   Jiri Olsa   perf tools: Add r...
65
  	cpu_map__put(cpus);
75562573b   Adrian Hunter   perf tools: Add s...
66
67
68
69
70
71
72
73
74
75
76
77
78
79
  
  	do {
  		ret = perf_do_probe_api(fn, cpu, try[i++]);
  		if (!ret)
  			return true;
  	} while (ret == -EAGAIN && try[i]);
  
  	return false;
  }
  
  static void perf_probe_sample_identifier(struct perf_evsel *evsel)
  {
  	evsel->attr.sample_type |= PERF_SAMPLE_IDENTIFIER;
  }
39e09d40b   Adrian Hunter   perf record: Sele...
80
81
82
83
  static void perf_probe_comm_exec(struct perf_evsel *evsel)
  {
  	evsel->attr.comm_exec = 1;
  }
b757bb091   Adrian Hunter   perf record: Add ...
84
85
86
87
  static void perf_probe_context_switch(struct perf_evsel *evsel)
  {
  	evsel->attr.context_switch = 1;
  }
75562573b   Adrian Hunter   perf tools: Add s...
88
89
90
91
  bool perf_can_sample_identifier(void)
  {
  	return perf_probe_api(perf_probe_sample_identifier);
  }
faf967068   Adrian Hunter   perf evlist: Move...
92

39e09d40b   Adrian Hunter   perf record: Sele...
93
94
95
96
  static bool perf_can_comm_exec(void)
  {
  	return perf_probe_api(perf_probe_comm_exec);
  }
b757bb091   Adrian Hunter   perf record: Add ...
97
98
99
100
  bool perf_can_record_switch_events(void)
  {
  	return perf_probe_api(perf_probe_context_switch);
  }
835095653   Adrian Hunter   perf tools: Add a...
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
  bool perf_can_record_cpu_wide(void)
  {
  	struct perf_event_attr attr = {
  		.type = PERF_TYPE_SOFTWARE,
  		.config = PERF_COUNT_SW_CPU_CLOCK,
  		.exclude_kernel = 1,
  	};
  	struct cpu_map *cpus;
  	int cpu, fd;
  
  	cpus = cpu_map__new(NULL);
  	if (!cpus)
  		return false;
  	cpu = cpus->map[0];
  	cpu_map__put(cpus);
  
  	fd = sys_perf_event_open(&attr, -1, cpu, -1, 0);
  	if (fd < 0)
  		return false;
  	close(fd);
  
  	return true;
  }
e68ae9cf7   Arnaldo Carvalho de Melo   perf evsel: Do no...
124
125
  void perf_evlist__config(struct perf_evlist *evlist, struct record_opts *opts,
  			 struct callchain_param *callchain)
faf967068   Adrian Hunter   perf evlist: Move...
126
127
  {
  	struct perf_evsel *evsel;
75562573b   Adrian Hunter   perf tools: Add s...
128
  	bool use_sample_identifier = false;
39e09d40b   Adrian Hunter   perf record: Sele...
129
  	bool use_comm_exec;
75562573b   Adrian Hunter   perf tools: Add s...
130

faf967068   Adrian Hunter   perf evlist: Move...
131
132
133
134
135
136
137
138
139
  	/*
  	 * Set the evsel leader links before we configure attributes,
  	 * since some might depend on this info.
  	 */
  	if (opts->group)
  		perf_evlist__set_leader(evlist);
  
  	if (evlist->cpus->map[0] < 0)
  		opts->no_inherit = true;
39e09d40b   Adrian Hunter   perf record: Sele...
140
  	use_comm_exec = perf_can_comm_exec();
e5cadb93d   Arnaldo Carvalho de Melo   perf evlist: Rena...
141
  	evlist__for_each_entry(evlist, evsel) {
e68ae9cf7   Arnaldo Carvalho de Melo   perf evsel: Do no...
142
  		perf_evsel__config(evsel, opts, callchain);
60b0896cc   Adrian Hunter   perf evlist: Add ...
143
  		if (evsel->tracking && use_comm_exec)
39e09d40b   Adrian Hunter   perf record: Sele...
144
145
  			evsel->attr.comm_exec = 1;
  	}
faf967068   Adrian Hunter   perf evlist: Move...
146

9e0cc4fe3   Adrian Hunter   perf auxtrace: Ad...
147
148
149
150
151
152
153
  	if (opts->full_auxtrace) {
  		/*
  		 * Need to be able to synthesize and parse selected events with
  		 * arbitrary sample types, which requires always being able to
  		 * match the id.
  		 */
  		use_sample_identifier = perf_can_sample_identifier();
e5cadb93d   Arnaldo Carvalho de Melo   perf evlist: Rena...
154
  		evlist__for_each_entry(evlist, evsel)
9e0cc4fe3   Adrian Hunter   perf auxtrace: Ad...
155
156
  			perf_evsel__set_sample_id(evsel, use_sample_identifier);
  	} else if (evlist->nr_entries > 1) {
75562573b   Adrian Hunter   perf tools: Add s...
157
  		struct perf_evsel *first = perf_evlist__first(evlist);
e5cadb93d   Arnaldo Carvalho de Melo   perf evlist: Rena...
158
  		evlist__for_each_entry(evlist, evsel) {
75562573b   Adrian Hunter   perf tools: Add s...
159
160
161
162
163
  			if (evsel->attr.sample_type == first->attr.sample_type)
  				continue;
  			use_sample_identifier = perf_can_sample_identifier();
  			break;
  		}
e5cadb93d   Arnaldo Carvalho de Melo   perf evlist: Rena...
164
  		evlist__for_each_entry(evlist, evsel)
75562573b   Adrian Hunter   perf tools: Add s...
165
  			perf_evsel__set_sample_id(evsel, use_sample_identifier);
faf967068   Adrian Hunter   perf evlist: Move...
166
  	}
75562573b   Adrian Hunter   perf tools: Add s...
167
168
  
  	perf_evlist__set_id_pos(evlist);
faf967068   Adrian Hunter   perf evlist: Move...
169
  }
714647bdc   Jiri Olsa   perf tools: Check...
170
171
172
  
  static int get_max_rate(unsigned int *rate)
  {
ce27309f6   Arnaldo Carvalho de Melo   perf tools: Use s...
173
  	return sysctl__read_int("kernel/perf_event_max_sample_rate", (int *)rate);
714647bdc   Jiri Olsa   perf tools: Check...
174
  }
b40067964   Arnaldo Carvalho de Melo   perf tools: Renam...
175
  static int record_opts__config_freq(struct record_opts *opts)
714647bdc   Jiri Olsa   perf tools: Check...
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
  {
  	bool user_freq = opts->user_freq != UINT_MAX;
  	unsigned int max_rate;
  
  	if (opts->user_interval != ULLONG_MAX)
  		opts->default_interval = opts->user_interval;
  	if (user_freq)
  		opts->freq = opts->user_freq;
  
  	/*
  	 * User specified count overrides default frequency.
  	 */
  	if (opts->default_interval)
  		opts->freq = 0;
  	else if (opts->freq) {
  		opts->default_interval = opts->freq;
  	} else {
  		pr_err("frequency and count are zero, aborting
  ");
  		return -1;
  	}
  
  	if (get_max_rate(&max_rate))
  		return 0;
  
  	/*
  	 * User specified frequency is over current maximum.
  	 */
  	if (user_freq && (max_rate < opts->freq)) {
  		pr_err("Maximum frequency rate (%u) reached.
  "
  		   "Please use -F freq option with lower value or consider
  "
  		   "tweaking /proc/sys/kernel/perf_event_max_sample_rate.
  ",
  		   max_rate);
  		return -1;
  	}
  
  	/*
  	 * Default frequency is over current maximum.
  	 */
  	if (max_rate < opts->freq) {
  		pr_warning("Lowering default frequency rate to %u.
  "
  			   "Please consider tweaking "
  			   "/proc/sys/kernel/perf_event_max_sample_rate.
  ",
  			   max_rate);
  		opts->freq = max_rate;
  	}
  
  	return 0;
  }
b40067964   Arnaldo Carvalho de Melo   perf tools: Renam...
230
  int record_opts__config(struct record_opts *opts)
714647bdc   Jiri Olsa   perf tools: Check...
231
  {
b40067964   Arnaldo Carvalho de Melo   perf tools: Renam...
232
  	return record_opts__config_freq(opts);
714647bdc   Jiri Olsa   perf tools: Check...
233
  }
c09ec6226   Adrian Hunter   perf evlist: Add ...
234
235
236
237
238
239
240
  
  bool perf_evlist__can_select_event(struct perf_evlist *evlist, const char *str)
  {
  	struct perf_evlist *temp_evlist;
  	struct perf_evsel *evsel;
  	int err, fd, cpu;
  	bool ret = false;
46ec69add   Adrian Hunter   perf tools: Fix p...
241
  	pid_t pid = -1;
c09ec6226   Adrian Hunter   perf evlist: Add ...
242
243
244
245
  
  	temp_evlist = perf_evlist__new();
  	if (!temp_evlist)
  		return false;
b39b83930   Jiri Olsa   perf tools: Add p...
246
  	err = parse_events(temp_evlist, str, NULL);
c09ec6226   Adrian Hunter   perf evlist: Add ...
247
248
249
250
251
252
253
254
255
  	if (err)
  		goto out_delete;
  
  	evsel = perf_evlist__last(temp_evlist);
  
  	if (!evlist || cpu_map__empty(evlist->cpus)) {
  		struct cpu_map *cpus = cpu_map__new(NULL);
  
  		cpu =  cpus ? cpus->map[0] : 0;
f30a79b01   Jiri Olsa   perf tools: Add r...
256
  		cpu_map__put(cpus);
c09ec6226   Adrian Hunter   perf evlist: Add ...
257
258
259
  	} else {
  		cpu = evlist->cpus->map[0];
  	}
46ec69add   Adrian Hunter   perf tools: Fix p...
260
261
262
263
264
265
266
267
268
269
270
  	while (1) {
  		fd = sys_perf_event_open(&evsel->attr, pid, cpu, -1,
  					 perf_event_open_cloexec_flag());
  		if (fd < 0) {
  			if (pid == -1 && errno == EACCES) {
  				pid = 0;
  				continue;
  			}
  			goto out_delete;
  		}
  		break;
c09ec6226   Adrian Hunter   perf evlist: Add ...
271
  	}
46ec69add   Adrian Hunter   perf tools: Fix p...
272
273
  	close(fd);
  	ret = true;
c09ec6226   Adrian Hunter   perf evlist: Add ...
274
275
276
277
278
  
  out_delete:
  	perf_evlist__delete(temp_evlist);
  	return ret;
  }