xref: /linux/tools/perf/builtin-trace.c (revision 709334c87dbdb44150ce436b3d13c814db0dcae9)
1 #include "builtin.h"
2 
3 #include "util/util.h"
4 #include "util/cache.h"
5 #include "util/symbol.h"
6 #include "util/thread.h"
7 #include "util/header.h"
8 #include "util/exec_cmd.h"
9 #include "util/trace-event.h"
10 
11 static char const		*script_name;
12 static char const		*generate_script_lang;
13 
14 static int default_start_script(const char *script __attribute((unused)))
15 {
16 	return 0;
17 }
18 
19 static int default_stop_script(void)
20 {
21 	return 0;
22 }
23 
24 static int default_generate_script(const char *outfile __attribute ((unused)))
25 {
26 	return 0;
27 }
28 
29 static struct scripting_ops default_scripting_ops = {
30 	.start_script		= default_start_script,
31 	.stop_script		= default_stop_script,
32 	.process_event		= print_event,
33 	.generate_script	= default_generate_script,
34 };
35 
36 static struct scripting_ops	*scripting_ops;
37 
38 static void setup_scripting(void)
39 {
40 	/* make sure PERF_EXEC_PATH is set for scripts */
41 	perf_set_argv_exec_path(perf_exec_path());
42 
43 	setup_perl_scripting();
44 
45 	scripting_ops = &default_scripting_ops;
46 }
47 
48 static int cleanup_scripting(void)
49 {
50 	return scripting_ops->stop_script();
51 }
52 
53 #include "util/parse-options.h"
54 
55 #include "perf.h"
56 #include "util/debug.h"
57 
58 #include "util/trace-event.h"
59 #include "util/data_map.h"
60 #include "util/exec_cmd.h"
61 
62 static char const		*input_name = "perf.data";
63 
64 static struct perf_header	*header;
65 static u64			sample_type;
66 
67 static int process_sample_event(event_t *event)
68 {
69 	struct sample_data data;
70 	struct thread *thread;
71 
72 	memset(&data, 0, sizeof(data));
73 	data.time = -1;
74 	data.cpu = -1;
75 	data.period = 1;
76 
77 	event__parse_sample(event, sample_type, &data);
78 
79 	dump_printf("(IP, %d): %d/%d: %p period: %Ld\n",
80 		event->header.misc,
81 		data.pid, data.tid,
82 		(void *)(long)data.ip,
83 		(long long)data.period);
84 
85 	thread = threads__findnew(event->ip.pid);
86 	if (thread == NULL) {
87 		pr_debug("problem processing %d event, skipping it.\n",
88 			 event->header.type);
89 		return -1;
90 	}
91 
92 	if (sample_type & PERF_SAMPLE_RAW) {
93 		/*
94 		 * FIXME: better resolve from pid from the struct trace_entry
95 		 * field, although it should be the same than this perf
96 		 * event pid
97 		 */
98 		scripting_ops->process_event(data.cpu, data.raw_data,
99 					     data.raw_size,
100 					     data.time, thread->comm);
101 	}
102 	event__stats.total += data.period;
103 
104 	return 0;
105 }
106 
107 static int sample_type_check(u64 type)
108 {
109 	sample_type = type;
110 
111 	if (!(sample_type & PERF_SAMPLE_RAW)) {
112 		fprintf(stderr,
113 			"No trace sample to read. Did you call perf record "
114 			"without -R?");
115 		return -1;
116 	}
117 
118 	return 0;
119 }
120 
121 static struct perf_file_handler file_handler = {
122 	.process_sample_event	= process_sample_event,
123 	.process_comm_event	= event__process_comm,
124 	.sample_type_check	= sample_type_check,
125 };
126 
127 static int __cmd_trace(void)
128 {
129 	register_idle_thread();
130 	register_perf_file_handler(&file_handler);
131 
132 	return mmap_dispatch_perf_file(&header, input_name,
133 				       0, 0, &event__cwdlen, &event__cwd);
134 }
135 
136 struct script_spec {
137 	struct list_head	node;
138 	struct scripting_ops	*ops;
139 	char			spec[0];
140 };
141 
142 LIST_HEAD(script_specs);
143 
144 static struct script_spec *script_spec__new(const char *spec,
145 					    struct scripting_ops *ops)
146 {
147 	struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
148 
149 	if (s != NULL) {
150 		strcpy(s->spec, spec);
151 		s->ops = ops;
152 	}
153 
154 	return s;
155 }
156 
157 static void script_spec__delete(struct script_spec *s)
158 {
159 	free(s->spec);
160 	free(s);
161 }
162 
163 static void script_spec__add(struct script_spec *s)
164 {
165 	list_add_tail(&s->node, &script_specs);
166 }
167 
168 static struct script_spec *script_spec__find(const char *spec)
169 {
170 	struct script_spec *s;
171 
172 	list_for_each_entry(s, &script_specs, node)
173 		if (strcasecmp(s->spec, spec) == 0)
174 			return s;
175 	return NULL;
176 }
177 
178 static struct script_spec *script_spec__findnew(const char *spec,
179 						struct scripting_ops *ops)
180 {
181 	struct script_spec *s = script_spec__find(spec);
182 
183 	if (s)
184 		return s;
185 
186 	s = script_spec__new(spec, ops);
187 	if (!s)
188 		goto out_delete_spec;
189 
190 	script_spec__add(s);
191 
192 	return s;
193 
194 out_delete_spec:
195 	script_spec__delete(s);
196 
197 	return NULL;
198 }
199 
200 int script_spec_register(const char *spec, struct scripting_ops *ops)
201 {
202 	struct script_spec *s;
203 
204 	s = script_spec__find(spec);
205 	if (s)
206 		return -1;
207 
208 	s = script_spec__findnew(spec, ops);
209 	if (!s)
210 		return -1;
211 
212 	return 0;
213 }
214 
215 static struct scripting_ops *script_spec__lookup(const char *spec)
216 {
217 	struct script_spec *s = script_spec__find(spec);
218 	if (!s)
219 		return NULL;
220 
221 	return s->ops;
222 }
223 
224 static void list_available_languages(void)
225 {
226 	struct script_spec *s;
227 
228 	fprintf(stderr, "\n");
229 	fprintf(stderr, "Scripting language extensions (used in "
230 		"perf trace -s [spec:]script.[spec]):\n\n");
231 
232 	list_for_each_entry(s, &script_specs, node)
233 		fprintf(stderr, "  %-42s [%s]\n", s->spec, s->ops->name);
234 
235 	fprintf(stderr, "\n");
236 }
237 
238 static int parse_scriptname(const struct option *opt __used,
239 			    const char *str, int unset __used)
240 {
241 	char spec[PATH_MAX];
242 	const char *script, *ext;
243 	int len;
244 
245 	if (strcmp(str, "list") == 0) {
246 		list_available_languages();
247 		return 0;
248 	}
249 
250 	script = strchr(str, ':');
251 	if (script) {
252 		len = script - str;
253 		if (len >= PATH_MAX) {
254 			fprintf(stderr, "invalid language specifier");
255 			return -1;
256 		}
257 		strncpy(spec, str, len);
258 		spec[len] = '\0';
259 		scripting_ops = script_spec__lookup(spec);
260 		if (!scripting_ops) {
261 			fprintf(stderr, "invalid language specifier");
262 			return -1;
263 		}
264 		script++;
265 	} else {
266 		script = str;
267 		ext = strchr(script, '.');
268 		if (!ext) {
269 			fprintf(stderr, "invalid script extension");
270 			return -1;
271 		}
272 		scripting_ops = script_spec__lookup(++ext);
273 		if (!scripting_ops) {
274 			fprintf(stderr, "invalid script extension");
275 			return -1;
276 		}
277 	}
278 
279 	script_name = strdup(script);
280 
281 	return 0;
282 }
283 
284 static const char * const annotate_usage[] = {
285 	"perf trace [<options>] <command>",
286 	NULL
287 };
288 
289 static const struct option options[] = {
290 	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
291 		    "dump raw trace in ASCII"),
292 	OPT_BOOLEAN('v', "verbose", &verbose,
293 		    "be more verbose (show symbol address, etc)"),
294 	OPT_BOOLEAN('l', "latency", &latency_format,
295 		    "show latency attributes (irqs/preemption disabled, etc)"),
296 	OPT_CALLBACK('s', "script", NULL, "name",
297 		     "script file name (lang:script name, script name, or *)",
298 		     parse_scriptname),
299 	OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
300 		   "generate perf-trace.xx script in specified language"),
301 
302 	OPT_END()
303 };
304 
305 int cmd_trace(int argc, const char **argv, const char *prefix __used)
306 {
307 	int err;
308 
309 	symbol__init(0);
310 
311 	setup_scripting();
312 
313 	argc = parse_options(argc, argv, options, annotate_usage, 0);
314 	if (argc) {
315 		/*
316 		 * Special case: if there's an argument left then assume tha
317 		 * it's a symbol filter:
318 		 */
319 		if (argc > 1)
320 			usage_with_options(annotate_usage, options);
321 	}
322 
323 	setup_pager();
324 
325 	if (generate_script_lang) {
326 		struct stat perf_stat;
327 
328 		int input = open(input_name, O_RDONLY);
329 		if (input < 0) {
330 			perror("failed to open file");
331 			exit(-1);
332 		}
333 
334 		err = fstat(input, &perf_stat);
335 		if (err < 0) {
336 			perror("failed to stat file");
337 			exit(-1);
338 		}
339 
340 		if (!perf_stat.st_size) {
341 			fprintf(stderr, "zero-sized file, nothing to do!\n");
342 			exit(0);
343 		}
344 
345 		scripting_ops = script_spec__lookup(generate_script_lang);
346 		if (!scripting_ops) {
347 			fprintf(stderr, "invalid language specifier");
348 			return -1;
349 		}
350 
351 		header = perf_header__new();
352 		if (header == NULL)
353 			return -1;
354 
355 		perf_header__read(header, input);
356 		err = scripting_ops->generate_script("perf-trace");
357 		goto out;
358 	}
359 
360 	if (script_name) {
361 		err = scripting_ops->start_script(script_name);
362 		if (err)
363 			goto out;
364 	}
365 
366 	err = __cmd_trace();
367 
368 	cleanup_scripting();
369 out:
370 	return err;
371 }
372