xref: /linux/tools/perf/builtin-trace.c (revision d39d0ed196aa1685bb24771e92f78633c66ac9cb)
1 #include "builtin.h"
2 
3 #include "perf.h"
4 #include "util/cache.h"
5 #include "util/debug.h"
6 #include "util/exec_cmd.h"
7 #include "util/header.h"
8 #include "util/parse-options.h"
9 #include "util/session.h"
10 #include "util/symbol.h"
11 #include "util/thread.h"
12 #include "util/trace-event.h"
13 #include "util/util.h"
14 
15 static char const		*script_name;
16 static char const		*generate_script_lang;
17 static bool			debug_mode;
18 static u64			last_timestamp;
19 static u64			nr_unordered;
20 
21 static int default_start_script(const char *script __unused,
22 				int argc __unused,
23 				const char **argv __unused)
24 {
25 	return 0;
26 }
27 
28 static int default_stop_script(void)
29 {
30 	return 0;
31 }
32 
33 static int default_generate_script(const char *outfile __unused)
34 {
35 	return 0;
36 }
37 
38 static struct scripting_ops default_scripting_ops = {
39 	.start_script		= default_start_script,
40 	.stop_script		= default_stop_script,
41 	.process_event		= print_event,
42 	.generate_script	= default_generate_script,
43 };
44 
45 static struct scripting_ops	*scripting_ops;
46 
47 static void setup_scripting(void)
48 {
49 	/* make sure PERF_EXEC_PATH is set for scripts */
50 	perf_set_argv_exec_path(perf_exec_path());
51 
52 	setup_perl_scripting();
53 	setup_python_scripting();
54 
55 	scripting_ops = &default_scripting_ops;
56 }
57 
58 static int cleanup_scripting(void)
59 {
60 	pr_debug("\nperf trace script stopped\n");
61 
62 	return scripting_ops->stop_script();
63 }
64 
65 static char const		*input_name = "perf.data";
66 
67 static int process_sample_event(event_t *event, struct perf_session *session)
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, session->sample_type, &data);
78 
79 	dump_printf("(IP, %d): %d/%d: %#Lx period: %Ld\n", event->header.misc,
80 		    data.pid, data.tid, data.ip, data.period);
81 
82 	thread = perf_session__findnew(session, event->ip.pid);
83 	if (thread == NULL) {
84 		pr_debug("problem processing %d event, skipping it.\n",
85 			 event->header.type);
86 		return -1;
87 	}
88 
89 	if (session->sample_type & PERF_SAMPLE_RAW) {
90 		if (debug_mode) {
91 			if (data.time < last_timestamp) {
92 				pr_err("Samples misordered, previous: %llu "
93 					"this: %llu\n", last_timestamp,
94 					data.time);
95 				nr_unordered++;
96 			}
97 			last_timestamp = data.time;
98 			return 0;
99 		}
100 		/*
101 		 * FIXME: better resolve from pid from the struct trace_entry
102 		 * field, although it should be the same than this perf
103 		 * event pid
104 		 */
105 		scripting_ops->process_event(data.cpu, data.raw_data,
106 					     data.raw_size,
107 					     data.time, thread->comm);
108 	}
109 
110 	session->hists.stats.total_period += data.period;
111 	return 0;
112 }
113 
114 static u64 nr_lost;
115 
116 static int process_lost_event(event_t *event, struct perf_session *session __used)
117 {
118 	nr_lost += event->lost.lost;
119 
120 	return 0;
121 }
122 
123 static struct perf_event_ops event_ops = {
124 	.sample	= process_sample_event,
125 	.comm	= event__process_comm,
126 	.attr	= event__process_attr,
127 	.event_type = event__process_event_type,
128 	.tracing_data = event__process_tracing_data,
129 	.build_id = event__process_build_id,
130 	.lost = process_lost_event,
131 	.ordered_samples = true,
132 };
133 
134 extern volatile int session_done;
135 
136 static void sig_handler(int sig __unused)
137 {
138 	session_done = 1;
139 }
140 
141 static int __cmd_trace(struct perf_session *session)
142 {
143 	int ret;
144 
145 	signal(SIGINT, sig_handler);
146 
147 	ret = perf_session__process_events(session, &event_ops);
148 
149 	if (debug_mode) {
150 		pr_err("Misordered timestamps: %llu\n", nr_unordered);
151 		pr_err("Lost events: %llu\n", nr_lost);
152 	}
153 
154 	return ret;
155 }
156 
157 struct script_spec {
158 	struct list_head	node;
159 	struct scripting_ops	*ops;
160 	char			spec[0];
161 };
162 
163 LIST_HEAD(script_specs);
164 
165 static struct script_spec *script_spec__new(const char *spec,
166 					    struct scripting_ops *ops)
167 {
168 	struct script_spec *s = malloc(sizeof(*s) + strlen(spec) + 1);
169 
170 	if (s != NULL) {
171 		strcpy(s->spec, spec);
172 		s->ops = ops;
173 	}
174 
175 	return s;
176 }
177 
178 static void script_spec__delete(struct script_spec *s)
179 {
180 	free(s->spec);
181 	free(s);
182 }
183 
184 static void script_spec__add(struct script_spec *s)
185 {
186 	list_add_tail(&s->node, &script_specs);
187 }
188 
189 static struct script_spec *script_spec__find(const char *spec)
190 {
191 	struct script_spec *s;
192 
193 	list_for_each_entry(s, &script_specs, node)
194 		if (strcasecmp(s->spec, spec) == 0)
195 			return s;
196 	return NULL;
197 }
198 
199 static struct script_spec *script_spec__findnew(const char *spec,
200 						struct scripting_ops *ops)
201 {
202 	struct script_spec *s = script_spec__find(spec);
203 
204 	if (s)
205 		return s;
206 
207 	s = script_spec__new(spec, ops);
208 	if (!s)
209 		goto out_delete_spec;
210 
211 	script_spec__add(s);
212 
213 	return s;
214 
215 out_delete_spec:
216 	script_spec__delete(s);
217 
218 	return NULL;
219 }
220 
221 int script_spec_register(const char *spec, struct scripting_ops *ops)
222 {
223 	struct script_spec *s;
224 
225 	s = script_spec__find(spec);
226 	if (s)
227 		return -1;
228 
229 	s = script_spec__findnew(spec, ops);
230 	if (!s)
231 		return -1;
232 
233 	return 0;
234 }
235 
236 static struct scripting_ops *script_spec__lookup(const char *spec)
237 {
238 	struct script_spec *s = script_spec__find(spec);
239 	if (!s)
240 		return NULL;
241 
242 	return s->ops;
243 }
244 
245 static void list_available_languages(void)
246 {
247 	struct script_spec *s;
248 
249 	fprintf(stderr, "\n");
250 	fprintf(stderr, "Scripting language extensions (used in "
251 		"perf trace -s [spec:]script.[spec]):\n\n");
252 
253 	list_for_each_entry(s, &script_specs, node)
254 		fprintf(stderr, "  %-42s [%s]\n", s->spec, s->ops->name);
255 
256 	fprintf(stderr, "\n");
257 }
258 
259 static int parse_scriptname(const struct option *opt __used,
260 			    const char *str, int unset __used)
261 {
262 	char spec[PATH_MAX];
263 	const char *script, *ext;
264 	int len;
265 
266 	if (strcmp(str, "lang") == 0) {
267 		list_available_languages();
268 		exit(0);
269 	}
270 
271 	script = strchr(str, ':');
272 	if (script) {
273 		len = script - str;
274 		if (len >= PATH_MAX) {
275 			fprintf(stderr, "invalid language specifier");
276 			return -1;
277 		}
278 		strncpy(spec, str, len);
279 		spec[len] = '\0';
280 		scripting_ops = script_spec__lookup(spec);
281 		if (!scripting_ops) {
282 			fprintf(stderr, "invalid language specifier");
283 			return -1;
284 		}
285 		script++;
286 	} else {
287 		script = str;
288 		ext = strchr(script, '.');
289 		if (!ext) {
290 			fprintf(stderr, "invalid script extension");
291 			return -1;
292 		}
293 		scripting_ops = script_spec__lookup(++ext);
294 		if (!scripting_ops) {
295 			fprintf(stderr, "invalid script extension");
296 			return -1;
297 		}
298 	}
299 
300 	script_name = strdup(script);
301 
302 	return 0;
303 }
304 
305 #define for_each_lang(scripts_dir, lang_dirent, lang_next)		\
306 	while (!readdir_r(scripts_dir, &lang_dirent, &lang_next) &&	\
307 	       lang_next)						\
308 		if (lang_dirent.d_type == DT_DIR &&			\
309 		    (strcmp(lang_dirent.d_name, ".")) &&		\
310 		    (strcmp(lang_dirent.d_name, "..")))
311 
312 #define for_each_script(lang_dir, script_dirent, script_next)		\
313 	while (!readdir_r(lang_dir, &script_dirent, &script_next) &&	\
314 	       script_next)						\
315 		if (script_dirent.d_type != DT_DIR)
316 
317 
318 #define RECORD_SUFFIX			"-record"
319 #define REPORT_SUFFIX			"-report"
320 
321 struct script_desc {
322 	struct list_head	node;
323 	char			*name;
324 	char			*half_liner;
325 	char			*args;
326 };
327 
328 LIST_HEAD(script_descs);
329 
330 static struct script_desc *script_desc__new(const char *name)
331 {
332 	struct script_desc *s = zalloc(sizeof(*s));
333 
334 	if (s != NULL)
335 		s->name = strdup(name);
336 
337 	return s;
338 }
339 
340 static void script_desc__delete(struct script_desc *s)
341 {
342 	free(s->name);
343 	free(s);
344 }
345 
346 static void script_desc__add(struct script_desc *s)
347 {
348 	list_add_tail(&s->node, &script_descs);
349 }
350 
351 static struct script_desc *script_desc__find(const char *name)
352 {
353 	struct script_desc *s;
354 
355 	list_for_each_entry(s, &script_descs, node)
356 		if (strcasecmp(s->name, name) == 0)
357 			return s;
358 	return NULL;
359 }
360 
361 static struct script_desc *script_desc__findnew(const char *name)
362 {
363 	struct script_desc *s = script_desc__find(name);
364 
365 	if (s)
366 		return s;
367 
368 	s = script_desc__new(name);
369 	if (!s)
370 		goto out_delete_desc;
371 
372 	script_desc__add(s);
373 
374 	return s;
375 
376 out_delete_desc:
377 	script_desc__delete(s);
378 
379 	return NULL;
380 }
381 
382 static char *ends_with(char *str, const char *suffix)
383 {
384 	size_t suffix_len = strlen(suffix);
385 	char *p = str;
386 
387 	if (strlen(str) > suffix_len) {
388 		p = str + strlen(str) - suffix_len;
389 		if (!strncmp(p, suffix, suffix_len))
390 			return p;
391 	}
392 
393 	return NULL;
394 }
395 
396 static char *ltrim(char *str)
397 {
398 	int len = strlen(str);
399 
400 	while (len && isspace(*str)) {
401 		len--;
402 		str++;
403 	}
404 
405 	return str;
406 }
407 
408 static int read_script_info(struct script_desc *desc, const char *filename)
409 {
410 	char line[BUFSIZ], *p;
411 	FILE *fp;
412 
413 	fp = fopen(filename, "r");
414 	if (!fp)
415 		return -1;
416 
417 	while (fgets(line, sizeof(line), fp)) {
418 		p = ltrim(line);
419 		if (strlen(p) == 0)
420 			continue;
421 		if (*p != '#')
422 			continue;
423 		p++;
424 		if (strlen(p) && *p == '!')
425 			continue;
426 
427 		p = ltrim(p);
428 		if (strlen(p) && p[strlen(p) - 1] == '\n')
429 			p[strlen(p) - 1] = '\0';
430 
431 		if (!strncmp(p, "description:", strlen("description:"))) {
432 			p += strlen("description:");
433 			desc->half_liner = strdup(ltrim(p));
434 			continue;
435 		}
436 
437 		if (!strncmp(p, "args:", strlen("args:"))) {
438 			p += strlen("args:");
439 			desc->args = strdup(ltrim(p));
440 			continue;
441 		}
442 	}
443 
444 	fclose(fp);
445 
446 	return 0;
447 }
448 
449 static int list_available_scripts(const struct option *opt __used,
450 				  const char *s __used, int unset __used)
451 {
452 	struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
453 	char scripts_path[MAXPATHLEN];
454 	DIR *scripts_dir, *lang_dir;
455 	char script_path[MAXPATHLEN];
456 	char lang_path[MAXPATHLEN];
457 	struct script_desc *desc;
458 	char first_half[BUFSIZ];
459 	char *script_root;
460 	char *str;
461 
462 	snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
463 
464 	scripts_dir = opendir(scripts_path);
465 	if (!scripts_dir)
466 		return -1;
467 
468 	for_each_lang(scripts_dir, lang_dirent, lang_next) {
469 		snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
470 			 lang_dirent.d_name);
471 		lang_dir = opendir(lang_path);
472 		if (!lang_dir)
473 			continue;
474 
475 		for_each_script(lang_dir, script_dirent, script_next) {
476 			script_root = strdup(script_dirent.d_name);
477 			str = ends_with(script_root, REPORT_SUFFIX);
478 			if (str) {
479 				*str = '\0';
480 				desc = script_desc__findnew(script_root);
481 				snprintf(script_path, MAXPATHLEN, "%s/%s",
482 					 lang_path, script_dirent.d_name);
483 				read_script_info(desc, script_path);
484 			}
485 			free(script_root);
486 		}
487 	}
488 
489 	fprintf(stdout, "List of available trace scripts:\n");
490 	list_for_each_entry(desc, &script_descs, node) {
491 		sprintf(first_half, "%s %s", desc->name,
492 			desc->args ? desc->args : "");
493 		fprintf(stdout, "  %-36s %s\n", first_half,
494 			desc->half_liner ? desc->half_liner : "");
495 	}
496 
497 	exit(0);
498 }
499 
500 static char *get_script_path(const char *script_root, const char *suffix)
501 {
502 	struct dirent *script_next, *lang_next, script_dirent, lang_dirent;
503 	char scripts_path[MAXPATHLEN];
504 	char script_path[MAXPATHLEN];
505 	DIR *scripts_dir, *lang_dir;
506 	char lang_path[MAXPATHLEN];
507 	char *str, *__script_root;
508 	char *path = NULL;
509 
510 	snprintf(scripts_path, MAXPATHLEN, "%s/scripts", perf_exec_path());
511 
512 	scripts_dir = opendir(scripts_path);
513 	if (!scripts_dir)
514 		return NULL;
515 
516 	for_each_lang(scripts_dir, lang_dirent, lang_next) {
517 		snprintf(lang_path, MAXPATHLEN, "%s/%s/bin", scripts_path,
518 			 lang_dirent.d_name);
519 		lang_dir = opendir(lang_path);
520 		if (!lang_dir)
521 			continue;
522 
523 		for_each_script(lang_dir, script_dirent, script_next) {
524 			__script_root = strdup(script_dirent.d_name);
525 			str = ends_with(__script_root, suffix);
526 			if (str) {
527 				*str = '\0';
528 				if (strcmp(__script_root, script_root))
529 					continue;
530 				snprintf(script_path, MAXPATHLEN, "%s/%s",
531 					 lang_path, script_dirent.d_name);
532 				path = strdup(script_path);
533 				free(__script_root);
534 				break;
535 			}
536 			free(__script_root);
537 		}
538 	}
539 
540 	return path;
541 }
542 
543 static const char * const trace_usage[] = {
544 	"perf trace [<options>] <command>",
545 	NULL
546 };
547 
548 static const struct option options[] = {
549 	OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
550 		    "dump raw trace in ASCII"),
551 	OPT_INCR('v', "verbose", &verbose,
552 		    "be more verbose (show symbol address, etc)"),
553 	OPT_BOOLEAN('L', "Latency", &latency_format,
554 		    "show latency attributes (irqs/preemption disabled, etc)"),
555 	OPT_CALLBACK_NOOPT('l', "list", NULL, NULL, "list available scripts",
556 			   list_available_scripts),
557 	OPT_CALLBACK('s', "script", NULL, "name",
558 		     "script file name (lang:script name, script name, or *)",
559 		     parse_scriptname),
560 	OPT_STRING('g', "gen-script", &generate_script_lang, "lang",
561 		   "generate perf-trace.xx script in specified language"),
562 	OPT_STRING('i', "input", &input_name, "file",
563 		    "input file name"),
564 	OPT_BOOLEAN('d', "debug-mode", &debug_mode,
565 		   "do various checks like samples ordering and lost events"),
566 
567 	OPT_END()
568 };
569 
570 int cmd_trace(int argc, const char **argv, const char *prefix __used)
571 {
572 	struct perf_session *session;
573 	const char *suffix = NULL;
574 	const char **__argv;
575 	char *script_path;
576 	int i, err;
577 
578 	if (argc >= 2 && strncmp(argv[1], "rec", strlen("rec")) == 0) {
579 		if (argc < 3) {
580 			fprintf(stderr,
581 				"Please specify a record script\n");
582 			return -1;
583 		}
584 		suffix = RECORD_SUFFIX;
585 	}
586 
587 	if (argc >= 2 && strncmp(argv[1], "rep", strlen("rep")) == 0) {
588 		if (argc < 3) {
589 			fprintf(stderr,
590 				"Please specify a report script\n");
591 			return -1;
592 		}
593 		suffix = REPORT_SUFFIX;
594 	}
595 
596 	if (!suffix && argc >= 2 && strncmp(argv[1], "-", strlen("-")) != 0) {
597 		char *record_script_path, *report_script_path;
598 		int live_pipe[2];
599 		pid_t pid;
600 
601 		record_script_path = get_script_path(argv[1], RECORD_SUFFIX);
602 		if (!record_script_path) {
603 			fprintf(stderr, "record script not found\n");
604 			return -1;
605 		}
606 
607 		report_script_path = get_script_path(argv[1], REPORT_SUFFIX);
608 		if (!report_script_path) {
609 			fprintf(stderr, "report script not found\n");
610 			return -1;
611 		}
612 
613 		if (pipe(live_pipe) < 0) {
614 			perror("failed to create pipe");
615 			exit(-1);
616 		}
617 
618 		pid = fork();
619 		if (pid < 0) {
620 			perror("failed to fork");
621 			exit(-1);
622 		}
623 
624 		if (!pid) {
625 			dup2(live_pipe[1], 1);
626 			close(live_pipe[0]);
627 
628 			__argv = malloc(5 * sizeof(const char *));
629 			__argv[0] = "/bin/sh";
630 			__argv[1] = record_script_path;
631 			__argv[2] = "-o";
632 			__argv[3] = "-";
633 			__argv[4] = NULL;
634 
635 			execvp("/bin/sh", (char **)__argv);
636 			exit(-1);
637 		}
638 
639 		dup2(live_pipe[0], 0);
640 		close(live_pipe[1]);
641 
642 		__argv = malloc((argc + 3) * sizeof(const char *));
643 		__argv[0] = "/bin/sh";
644 		__argv[1] = report_script_path;
645 		for (i = 2; i < argc; i++)
646 			__argv[i] = argv[i];
647 		__argv[i++] = "-i";
648 		__argv[i++] = "-";
649 		__argv[i++] = NULL;
650 
651 		execvp("/bin/sh", (char **)__argv);
652 		exit(-1);
653 	}
654 
655 	if (suffix) {
656 		script_path = get_script_path(argv[2], suffix);
657 		if (!script_path) {
658 			fprintf(stderr, "script not found\n");
659 			return -1;
660 		}
661 
662 		__argv = malloc((argc + 1) * sizeof(const char *));
663 		__argv[0] = "/bin/sh";
664 		__argv[1] = script_path;
665 		for (i = 3; i < argc; i++)
666 			__argv[i - 1] = argv[i];
667 		__argv[argc - 1] = NULL;
668 
669 		execvp("/bin/sh", (char **)__argv);
670 		exit(-1);
671 	}
672 
673 	setup_scripting();
674 
675 	argc = parse_options(argc, argv, options, trace_usage,
676 			     PARSE_OPT_STOP_AT_NON_OPTION);
677 
678 	if (symbol__init() < 0)
679 		return -1;
680 	if (!script_name)
681 		setup_pager();
682 
683 	session = perf_session__new(input_name, O_RDONLY, 0, false);
684 	if (session == NULL)
685 		return -ENOMEM;
686 
687 	if (strcmp(input_name, "-") &&
688 	    !perf_session__has_traces(session, "record -R"))
689 		return -EINVAL;
690 
691 	if (generate_script_lang) {
692 		struct stat perf_stat;
693 
694 		int input = open(input_name, O_RDONLY);
695 		if (input < 0) {
696 			perror("failed to open file");
697 			exit(-1);
698 		}
699 
700 		err = fstat(input, &perf_stat);
701 		if (err < 0) {
702 			perror("failed to stat file");
703 			exit(-1);
704 		}
705 
706 		if (!perf_stat.st_size) {
707 			fprintf(stderr, "zero-sized file, nothing to do!\n");
708 			exit(0);
709 		}
710 
711 		scripting_ops = script_spec__lookup(generate_script_lang);
712 		if (!scripting_ops) {
713 			fprintf(stderr, "invalid language specifier");
714 			return -1;
715 		}
716 
717 		err = scripting_ops->generate_script("perf-trace");
718 		goto out;
719 	}
720 
721 	if (script_name) {
722 		err = scripting_ops->start_script(script_name, argc, argv);
723 		if (err)
724 			goto out;
725 		pr_debug("perf trace started with script %s\n\n", script_name);
726 	}
727 
728 	err = __cmd_trace(session);
729 
730 	perf_session__delete(session);
731 	cleanup_scripting();
732 out:
733 	return err;
734 }
735