xref: /aosp_15_r20/external/trace-cmd/tracecmd/trace-read.c (revision 58e6ee5f017f6a8912852c892d18457e4bafb554)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <[email protected]>
4  *
5  */
6 #define _LARGEFILE64_SOURCE
7 #include <dirent.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <getopt.h>
12 #include <stdarg.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15 #include <sys/wait.h>
16 #include <sys/mman.h>
17 #include <fcntl.h>
18 #include <signal.h>
19 #include <unistd.h>
20 #include <ctype.h>
21 #include <errno.h>
22 
23 #include "trace-local.h"
24 #include "trace-hash.h"
25 #include "trace-hash-local.h"
26 #include "kbuffer.h"
27 #include "list.h"
28 
29 /*
30  * tep_func_repeat_format is defined as a weak variable in the
31  * libtraceevent library function plugin, to allow applications
32  * to override the format of the timestamp it prints for the
33  * last function that repeated.
34  */
35 const char *tep_func_repeat_format;
36 
37 static struct filter_str {
38 	struct filter_str	*next;
39 	char			*filter;
40 	int			neg;
41 } *filter_strings;
42 static struct filter_str **filter_next = &filter_strings;
43 
44 struct filter {
45 	struct filter		*next;
46 	struct tep_event_filter	*filter;
47 };
48 
49 struct event_str {
50 	struct event_str	*next;
51 	const char		*event;
52 };
53 
54 struct handle_list {
55 	struct list_head	list;
56 	struct tracecmd_input	*handle;
57 	const char		*file;
58 	int			cpus;
59 	int			done;
60 	struct tep_record	*record;
61 	struct filter		*event_filters;
62 	struct filter		*event_filter_out;
63 	unsigned long long	*last_timestamp;
64 };
65 static struct list_head handle_list;
66 
67 struct input_files {
68 	struct list_head	list;
69 	const char		*file;
70 	long long		tsoffset;
71 	unsigned long long	ts2secs;
72 };
73 static struct list_head input_files;
74 static struct input_files *last_input_file;
75 
76 struct pid_list {
77 	struct pid_list		*next;
78 	char			*pid;
79 	int			free;
80 } *pid_list;
81 
82 struct pid_list *comm_list;
83 
84 static unsigned int page_size;
85 static int input_fd;
86 static const char *default_input_file = DEFAULT_INPUT_FILE;
87 static const char *input_file;
88 static int multi_inputs;
89 static int max_file_size;
90 
91 static int instances;
92 
93 static int *filter_cpus;
94 static int nr_filter_cpus;
95 static int test_filters_mode;
96 
97 static int show_wakeup;
98 static int wakeup_id;
99 static int wakeup_new_id;
100 static int sched_id;
101 static int stacktrace_id;
102 
103 static int profile;
104 
105 static int buffer_breaks = 0;
106 
107 static int no_irqs;
108 static int no_softirqs;
109 
110 static int tsdiff;
111 static int tscheck;
112 
113 static int latency_format;
114 static bool raw_format;
115 static const char *format_type = TEP_PRINT_INFO;
116 
117 static struct tep_format_field *wakeup_task;
118 static struct tep_format_field *wakeup_success;
119 static struct tep_format_field *wakeup_new_task;
120 static struct tep_format_field *wakeup_new_success;
121 static struct tep_format_field *sched_task;
122 static struct tep_format_field *sched_prio;
123 
124 static unsigned long long total_wakeup_lat;
125 static unsigned long wakeup_lat_count;
126 
127 static unsigned long long total_wakeup_rt_lat;
128 static unsigned long wakeup_rt_lat_count;
129 
130 struct wakeup_info {
131 	struct trace_hash_item	hash;
132 	unsigned long long	start;
133 	int			pid;
134 };
135 
136 static struct hook_list *hooks;
137 static struct hook_list *last_hook;
138 
139 #define WAKEUP_HASH_SIZE 1024
140 static struct trace_hash wakeup_hash;
141 
print_event_name(struct trace_seq * s,struct tep_event * event)142 static void print_event_name(struct trace_seq *s, struct tep_event *event)
143 {
144 	static const char *spaces = "                    "; /* 20 spaces */
145 	const char *name;
146 	int len;
147 
148 	name = event ? event->name : "(NULL)";
149 
150 	trace_seq_printf(s, " %s: ", name);
151 
152 	/* Space out the event names evenly. */
153 	len = strlen(name);
154 	if (len < 20)
155 		trace_seq_printf(s, "%.*s", 20 - len, spaces);
156 }
157 
158 enum time_fmt {
159 	TIME_FMT_LAT		= 1,
160 	TIME_FMT_NORMAL		= 2,
161 };
162 
time_format(struct tracecmd_input * handle,enum time_fmt tf)163 static const char *time_format(struct tracecmd_input *handle, enum time_fmt tf)
164 {
165 	struct tep_handle *tep = tracecmd_get_tep(handle);
166 
167 	switch (tf) {
168 	case TIME_FMT_LAT:
169 		if (latency_format)
170 			return "%8.8s-%-5d %3d";
171 		return "%16s-%-5d [%03d]";
172 	default:
173 		if (tracecmd_get_flags(handle) & TRACECMD_FL_IN_USECS) {
174 			if (tep_test_flag(tep, TEP_NSEC_OUTPUT))
175 				return " %9.1d:";
176 			else
177 				return " %6.1000d:";
178 		} else
179 			return "%12d:";
180 	}
181 }
182 
print_event(struct trace_seq * s,struct tracecmd_input * handle,struct tep_record * record)183 static void print_event(struct trace_seq *s, struct tracecmd_input *handle,
184 			struct tep_record *record)
185 {
186 	struct tep_handle *tep = tracecmd_get_tep(handle);
187 	struct tep_event *event;
188 	const char *lfmt = time_format(handle, TIME_FMT_LAT);
189 	const char *tfmt = time_format(handle, TIME_FMT_NORMAL);
190 
191 	event = tep_find_event_by_record(tep, record);
192 	tep_print_event(tep, s, record, lfmt, TEP_PRINT_COMM,
193 			TEP_PRINT_PID, TEP_PRINT_CPU);
194 	tep_print_event(tep, s, record, tfmt, TEP_PRINT_TIME);
195 	print_event_name(s, event);
196 	tep_print_event(tep, s, record, "%s", format_type);
197 }
198 
199 /* Debug variables for testing tracecmd_read_at */
200 #define TEST_READ_AT 0
201 #if TEST_READ_AT
202 #define DO_TEST
203 static off64_t test_read_at_offset;
204 static int test_read_at_copy = 100;
205 static int test_read_at_index;
show_test(struct tracecmd_input * handle)206 static void show_test(struct tracecmd_input *handle)
207 {
208 	struct tep_record *record;
209 	struct trace_seq s;
210 
211 	if (!test_read_at_offset) {
212 		printf("\nNO RECORD COPIED\n");
213 		return;
214 	}
215 
216 	record = tracecmd_read_at(handle, test_read_at_offset, NULL);
217 	printf("\nHERE'S THE COPY RECORD\n");
218 	trace_seq_init(&s);
219 	print_event(&s, handle, record);
220 	trace_seq_do_printf(&s);
221 	trace_seq_destroy(&s);
222 	printf("\n");
223 
224 	tracecmd_free_record(record);
225 }
226 
test_save(struct tep_record * record,int cpu)227 static void test_save(struct tep_record *record, int cpu)
228 {
229 	if (test_read_at_index++ == test_read_at_copy) {
230 		test_read_at_offset = record->offset;
231 		printf("\nUSING THIS RECORD\n");
232 	}
233 }
234 #endif /* TEST_READ_AT */
235 
236 /* Debug variables for testing tracecmd_set_cpu_at_timestamp */
237 #define TEST_AT_TIMESTAMP 0
238 #if TEST_AT_TIMESTAMP
239 #define DO_TEST
240 static unsigned long long test_at_timestamp_ts;
241 static int test_at_timestamp_copy = 100;
242 static int test_at_timestamp_cpu = -1;
243 static int test_at_timestamp_index;
show_test(struct tracecmd_input * handle)244 static void show_test(struct tracecmd_input *handle)
245 {
246 	struct tep_record *record;
247 	struct trace_seq s;
248 	int cpu = test_at_timestamp_cpu;
249 
250 	if (!test_at_timestamp_ts) {
251 		printf("\nNO RECORD COPIED\n");
252 		return;
253 	}
254 
255 	if (tracecmd_set_cpu_to_timestamp(handle, cpu, test_at_timestamp_ts))
256 		return;
257 
258 	record = tracecmd_read_data(handle, cpu);
259 	printf("\nHERE'S THE COPY RECORD with page %p offset=%p\n",
260 	       (void *)(record->offset & ~(page_size - 1)),
261 	       (void *)record->offset);
262 	trace_seq_init(&s);
263 	print_event(&s, handle, record);
264 	trace_seq_do_printf(&s);
265 	trace_seq_destroy(&s);
266 	printf("\n");
267 
268 	tracecmd_free_record(record);
269 }
270 
test_save(struct tep_record * record,int cpu)271 static void test_save(struct tep_record *record, int cpu)
272 {
273 	if (test_at_timestamp_index++ == test_at_timestamp_copy) {
274 		test_at_timestamp_ts = record->ts;
275 		test_at_timestamp_cpu = cpu;
276 		printf("\nUSING THIS RECORD page=%p offset=%p\n",
277 		       (void *)(record->offset & ~(page_size - 1)),
278 		       (void *)record->offset);
279 	}
280 }
281 #endif /* TEST_AT_TIMESTAMP */
282 
283 #define TEST_FIRST_LAST 0
284 #if TEST_FIRST_LAST
285 #define DO_TEST
show_test(struct tracecmd_input * handle)286 static void show_test(struct tracecmd_input *handle)
287 {
288 	struct tep_record *record;
289 	struct trace_seq s;
290 	int cpu = 0;
291 
292 	record = tracecmd_read_cpu_first(handle, cpu);
293 	if (!record) {
294 		printf("No first record?\n");
295 		return;
296 	}
297 
298 	printf("\nHERE'S THE FIRST RECORD with offset %p\n",
299 	       (void *)record->offset);
300 	trace_seq_init(&s);
301 	print_event(&s, handle, record);
302 	trace_seq_do_printf(&s);
303 	trace_seq_destroy(&s);
304 	printf("\n");
305 
306 	tracecmd_free_record(record);
307 
308 	record = tracecmd_read_cpu_last(handle, cpu);
309 	if (!record) {
310 		printf("No last record?\n");
311 		return;
312 	}
313 
314 	printf("\nHERE'S THE LAST RECORD with offset %p\n",
315 	       (void *)record->offset);
316 	trace_seq_init(&s);
317 	print_event(&s, handle, record);
318 	trace_seq_do_printf(&s);
319 	trace_seq_destroy(&s);
320 	printf("\n");
321 
322 	tracecmd_free_record(record);
323 }
test_save(struct tep_record * record,int cpu)324 static void test_save(struct tep_record *record, int cpu)
325 {
326 }
327 #endif /* TEST_FIRST_LAST */
328 
329 #ifndef DO_TEST
show_test(struct tracecmd_input * handle)330 static void show_test(struct tracecmd_input *handle)
331 {
332 	/* quiet the compiler */
333 	if (0)
334 		print_event(NULL, NULL, NULL);
335 }
test_save(struct tep_record * record,int cpu)336 static void test_save(struct tep_record *record, int cpu)
337 {
338 }
339 #endif
340 
add_input(const char * file)341 static void add_input(const char *file)
342 {
343 	struct input_files *item;
344 
345 	item = malloc(sizeof(*item));
346 	if (!item)
347 		die("Failed to allocate for %s", file);
348 	memset(item, 0, sizeof(*item));
349 	item->file = file;
350 	list_add_tail(&item->list, &input_files);
351 	last_input_file = item;
352 }
353 
add_handle(struct tracecmd_input * handle,const char * file)354 static void add_handle(struct tracecmd_input *handle, const char *file)
355 {
356 	struct handle_list *item;
357 
358 	item = malloc(sizeof(*item));
359 	if (!item)
360 		die("Failed ot allocate for %s", file);
361 	memset(item, 0, sizeof(*item));
362 	item->handle = handle;
363 	if (file) {
364 		item->file = file + strlen(file);
365 		/* we want just the base name */
366 		while (item->file >= file && *item->file != '/')
367 			item->file--;
368 		item->file++;
369 		if (strlen(item->file) > max_file_size)
370 			max_file_size = strlen(item->file);
371 	}
372 	list_add_tail(&item->list, &handle_list);
373 }
374 
free_inputs(void)375 static void free_inputs(void)
376 {
377 	struct input_files *item;
378 
379 	while (!list_empty(&input_files)) {
380 		item = container_of(input_files.next, struct input_files, list);
381 		list_del(&item->list);
382 		free(item);
383 	}
384 }
385 
free_handles(void)386 static void free_handles(void)
387 {
388 	struct handle_list *item;
389 
390 	while (!list_empty(&handle_list)) {
391 		item = container_of(handle_list.next, struct handle_list, list);
392 		list_del(&item->list);
393 		free(item);
394 	}
395 }
396 
add_filter(const char * filter,int neg)397 static void add_filter(const char *filter, int neg)
398 {
399 	struct filter_str *ftr;
400 
401 	ftr = malloc(sizeof(*ftr));
402 	if (!ftr)
403 		die("Failed to allocate for filter %s", filter);
404 	ftr->filter = strdup(filter);
405 	if (!ftr->filter)
406 		die("malloc");
407 	ftr->next = NULL;
408 	ftr->neg = neg;
409 
410 	/* must maintain order of command line */
411 	*filter_next = ftr;
412 	filter_next = &ftr->next;
413 }
414 
__add_filter(struct pid_list ** head,const char * arg)415 static void __add_filter(struct pid_list **head, const char *arg)
416 {
417 	struct pid_list *list;
418 	char *pids = strdup(arg);
419 	char *pid;
420 	char *sav;
421 	int free = 1;
422 
423 	if (!pids)
424 		die("malloc");
425 
426 	pid = strtok_r(pids, ",", &sav);
427 	while (pid) {
428 		list = malloc(sizeof(*list));
429 		if (!list)
430 			die("Failed to allocate for arg %s", arg);
431 		list->pid = pid;
432 		list->free = free;
433 		list->next = *head;
434 		*head = list;
435 		/* The first pid needs to be freed */
436 		free = 0;
437 		pid = strtok_r(NULL, ",", &sav);
438 	}
439 }
440 
add_comm_filter(const char * arg)441 static void add_comm_filter(const char *arg)
442 {
443 	__add_filter(&comm_list, arg);
444 }
445 
add_pid_filter(const char * arg)446 static void add_pid_filter(const char *arg)
447 {
448 	__add_filter(&pid_list, arg);
449 }
450 
append_pid_filter(char * curr_filter,char * pid)451 static char *append_pid_filter(char *curr_filter, char *pid)
452 {
453 	char *filter;
454 	int len, curr_len;
455 
456 #define FILTER_FMT "(common_pid==" __STR ")||(pid==" __STR ")||(next_pid==" __STR ")"
457 
458 #undef __STR
459 #define __STR ""
460 
461 	/* strlen(".*:") > strlen("||") */
462 	len = strlen(".*:" FILTER_FMT) + strlen(pid) * 3 + 1;
463 
464 #undef __STR
465 #define __STR "%s"
466 
467 	if (!curr_filter) {
468 		filter = malloc(len);
469 		if (!filter)
470 			die("Failed to allocate for filter %s", curr_filter);
471 		sprintf(filter, ".*:" FILTER_FMT, pid, pid, pid);
472 	} else {
473 		curr_len = strlen(curr_filter);
474 		len += curr_len;
475 
476 		filter = realloc(curr_filter, len);
477 		if (!filter)
478 			die("realloc");
479 		sprintf(filter + curr_len, "||" FILTER_FMT, pid, pid, pid);
480 	}
481 
482 	return filter;
483 }
484 
convert_comm_filter(struct tracecmd_input * handle)485 static void convert_comm_filter(struct tracecmd_input *handle)
486 {
487 	struct tep_cmdline *cmdline;
488 	struct tep_handle *pevent;
489 	struct pid_list *list;
490 
491 	char pidstr[100];
492 
493 	if (!comm_list)
494 		return;
495 
496 	pevent = tracecmd_get_tep(handle);
497 
498 	/* Seach for comm names and get their pids */
499 	for (list = comm_list; list; list = list->next) {
500 		cmdline = tep_data_pid_from_comm(pevent, list->pid, NULL);
501 		if (!cmdline) {
502 			warning("comm: %s not in cmdline list", list->pid);
503 			continue;
504 		}
505 		do {
506 			sprintf(pidstr, "%d", tep_cmdline_pid(pevent, cmdline));
507 			add_pid_filter(pidstr);
508 			cmdline = tep_data_pid_from_comm(pevent, list->pid,
509 							    cmdline);
510 		} while (cmdline);
511 	}
512 
513 	while (comm_list) {
514 		list = comm_list;
515 		comm_list = comm_list->next;
516 		if (list->free)
517 			free(list->pid);
518 		free(list);
519 	}
520 }
521 
make_pid_filter(struct tracecmd_input * handle)522 static void make_pid_filter(struct tracecmd_input *handle)
523 {
524 	struct pid_list *list;
525 	char *str = NULL;
526 
527 	convert_comm_filter(handle);
528 
529 	if (!pid_list)
530 		return;
531 
532 	/* First do all common pids */
533 	for (list = pid_list; list; list = list->next) {
534 		str = append_pid_filter(str, list->pid);
535 	}
536 
537 	add_filter(str, 0);
538 	free(str);
539 
540 	while (pid_list) {
541 		list = pid_list;
542 		pid_list = pid_list->next;
543 		if (list->free)
544 			free(list->pid);
545 		free(list);
546 	}
547 }
548 
process_filters(struct handle_list * handles)549 static void process_filters(struct handle_list *handles)
550 {
551 	struct filter **filter_next = &handles->event_filters;
552 	struct filter **filter_out_next = &handles->event_filter_out;
553 	struct filter *event_filter;
554 	struct filter_str *filter;
555 	struct tep_handle *pevent;
556 	char errstr[200];
557 	int filters = 0;
558 	int ret;
559 
560 	pevent = tracecmd_get_tep(handles->handle);
561 
562 	make_pid_filter(handles->handle);
563 
564 	while (filter_strings) {
565 		filter = filter_strings;
566 		filter_strings = filter->next;
567 
568 		event_filter = malloc(sizeof(*event_filter));
569 		if (!event_filter)
570 			die("Failed to allocate for event filter");
571 		event_filter->next = NULL;
572 		event_filter->filter = tep_filter_alloc(pevent);
573 		if (!event_filter->filter)
574 			die("malloc");
575 
576 		ret = tep_filter_add_filter_str(event_filter->filter,
577 						   filter->filter);
578 		if (ret < 0) {
579 			tep_strerror(pevent, ret, errstr, sizeof(errstr));
580 			die("Error filtering: %s\n%s",
581 			    filter->filter, errstr);
582 		}
583 
584 		if (filter->neg) {
585 			*filter_out_next = event_filter;
586 			filter_out_next = &event_filter->next;
587 		} else {
588 			*filter_next = event_filter;
589 			filter_next = &event_filter->next;
590 		}
591 		filters++;
592 		free(filter->filter);
593 		free(filter);
594 	}
595 	if (filters && test_filters_mode)
596 		exit(0);
597 }
598 
init_wakeup(struct tracecmd_input * handle)599 static void init_wakeup(struct tracecmd_input *handle)
600 {
601 	struct tep_handle *pevent;
602 	struct tep_event *event;
603 
604 	if (!show_wakeup)
605 		return;
606 
607 	pevent = tracecmd_get_tep(handle);
608 
609 	trace_hash_init(&wakeup_hash, WAKEUP_HASH_SIZE);
610 
611 	event = tep_find_event_by_name(pevent, "sched", "sched_wakeup");
612 	if (!event)
613 		goto fail;
614 	wakeup_id = event->id;
615 	wakeup_task = tep_find_field(event, "pid");
616 	if (!wakeup_task)
617 		goto fail;
618 	wakeup_success = tep_find_field(event, "success");
619 
620 	event = tep_find_event_by_name(pevent, "sched", "sched_switch");
621 	if (!event)
622 		goto fail;
623 	sched_id = event->id;
624 	sched_task = tep_find_field(event, "next_pid");
625 	if (!sched_task)
626 		goto fail;
627 
628 	sched_prio = tep_find_field(event, "next_prio");
629 	if (!sched_prio)
630 		goto fail;
631 
632 
633 	wakeup_new_id = -1;
634 
635 	event = tep_find_event_by_name(pevent, "sched", "sched_wakeup_new");
636 	if (!event)
637 		goto skip;
638 	wakeup_new_id = event->id;
639 	wakeup_new_task = tep_find_field(event, "pid");
640 	if (!wakeup_new_task)
641 		goto fail;
642 	wakeup_new_success = tep_find_field(event, "success");
643 
644  skip:
645 	return;
646 
647  fail:
648 	show_wakeup = 0;
649 }
650 
add_wakeup(unsigned int val,unsigned long long start)651 static void add_wakeup(unsigned int val, unsigned long long start)
652 {
653 	unsigned int key = trace_hash(val);
654 	struct wakeup_info *info;
655 	struct trace_hash_item *item;
656 
657 	item = trace_hash_find(&wakeup_hash, key, NULL, NULL);
658 	if (item) {
659 		info = container_of(item, struct wakeup_info, hash);
660 		/* Hmm, double wakeup? */
661 		info->start = start;
662 		return;
663 	}
664 
665 	info = malloc(sizeof(*info));
666 	if (!info)
667 		die("Failed to allocate wakeup info");
668 	info->hash.key = key;
669 	info->start = start;
670 	trace_hash_add(&wakeup_hash, &info->hash);
671 }
672 
673 static unsigned long long max_lat = 0;
674 static unsigned long long max_time;
675 static unsigned long long min_lat = -1;
676 static unsigned long long min_time;
677 
678 static unsigned long long max_rt_lat = 0;
679 static unsigned long long max_rt_time;
680 static unsigned long long min_rt_lat = -1;
681 static unsigned long long min_rt_time;
682 
add_sched(unsigned int val,unsigned long long end,int rt)683 static void add_sched(unsigned int val, unsigned long long end, int rt)
684 {
685 	struct trace_hash_item *item;
686 	unsigned int key = trace_hash(val);
687 	struct wakeup_info *info;
688 	unsigned long long cal;
689 
690 	item = trace_hash_find(&wakeup_hash, key, NULL, NULL);
691 	if (!item)
692 		return;
693 
694 	info = container_of(item, struct wakeup_info, hash);
695 
696 	cal = end - info->start;
697 
698 	if (cal > max_lat) {
699 		max_lat = cal;
700 		max_time = end;
701 	}
702 	if (cal < min_lat) {
703 		min_lat = cal;
704 		min_time = end;
705 	}
706 
707 	if (rt) {
708 		if (cal > max_rt_lat) {
709 			max_rt_lat = cal;
710 			max_rt_time = end;
711 		}
712 		if (cal < min_rt_lat) {
713 			min_rt_lat = cal;
714 			min_rt_time = end;
715 		}
716 	}
717 
718 	printf(" Latency: %llu.%03llu usecs", cal / 1000, cal % 1000);
719 
720 	total_wakeup_lat += cal;
721 	wakeup_lat_count++;
722 
723 	if (rt) {
724 		total_wakeup_rt_lat += cal;
725 		wakeup_rt_lat_count++;
726 	}
727 
728 	trace_hash_del(item);
729 	free(info);
730 }
731 
process_wakeup(struct tep_handle * pevent,struct tep_record * record)732 static void process_wakeup(struct tep_handle *pevent, struct tep_record *record)
733 {
734 	unsigned long long val;
735 	int id;
736 
737 	if (!show_wakeup)
738 		return;
739 
740 	id = tep_data_type(pevent, record);
741 	if (id == wakeup_id) {
742 		if (tep_read_number_field(wakeup_success, record->data, &val) == 0) {
743 			if (!val)
744 				return;
745 		}
746 		if (tep_read_number_field(wakeup_task, record->data, &val))
747 			return;
748 		add_wakeup(val, record->ts);
749 	} else if (id == wakeup_new_id) {
750 		if (tep_read_number_field(wakeup_new_success, record->data, &val) == 0) {
751 			if (!val)
752 				return;
753 		}
754 		if (tep_read_number_field(wakeup_new_task, record->data, &val))
755 			return;
756 		add_wakeup(val, record->ts);
757 	} else if (id == sched_id) {
758 		int rt = 1;
759 		if (tep_read_number_field(sched_prio, record->data, &val))
760 			return;
761 		if (val > 99)
762 			rt = 0;
763 		if (tep_read_number_field(sched_task, record->data, &val))
764 			return;
765 		add_sched(val, record->ts, rt);
766 	}
767 }
768 
769 static void
show_wakeup_timings(unsigned long long total,unsigned long count,unsigned long long lat_max,unsigned long long time_max,unsigned long long lat_min,unsigned long long time_min)770 show_wakeup_timings(unsigned long long total, unsigned long count,
771 		    unsigned long long lat_max, unsigned long long time_max,
772 		    unsigned long long lat_min, unsigned long long time_min)
773 {
774 
775 	total /= count;
776 
777 	printf("\nAverage wakeup latency: %llu.%03llu usecs\n",
778 	       total / 1000,
779 	       total % 1000);
780 	printf("Maximum Latency: %llu.%03llu usecs at ", lat_max / 1000, lat_max % 1000);
781 	printf("timestamp: %llu.%06llu\n",
782 	       time_max / 1000000000, ((time_max + 500) % 1000000000) / 1000);
783 	printf("Minimum Latency: %llu.%03llu usecs at ", lat_min / 1000, lat_min % 1000);
784 	printf("timestamp: %llu.%06llu\n\n", time_min / 1000000000,
785 	       ((time_min + 500) % 1000000000) / 1000);
786 }
787 
finish_wakeup(void)788 static void finish_wakeup(void)
789 {
790 	struct wakeup_info *info;
791 	struct trace_hash_item **bucket;
792 	struct trace_hash_item *item;
793 
794 	if (!show_wakeup || !wakeup_lat_count)
795 		return;
796 
797 	show_wakeup_timings(total_wakeup_lat, wakeup_lat_count,
798 			    max_lat, max_time,
799 			    min_lat, min_time);
800 
801 
802 	if (wakeup_rt_lat_count) {
803 		printf("RT task timings:\n");
804 		show_wakeup_timings(total_wakeup_rt_lat, wakeup_rt_lat_count,
805 				    max_rt_lat, max_rt_time,
806 				    min_rt_lat, min_rt_time);
807 	}
808 
809 	trace_hash_for_each_bucket(bucket, &wakeup_hash) {
810 		trace_hash_while_item(item, bucket) {
811 			trace_hash_del(item);
812 			info = container_of(item, struct wakeup_info, hash);
813 			free(info);
814 		}
815 	}
816 
817 	trace_hash_free(&wakeup_hash);
818 }
819 
trace_show_data(struct tracecmd_input * handle,struct tep_record * record)820 void trace_show_data(struct tracecmd_input *handle, struct tep_record *record)
821 {
822 	tracecmd_show_data_func func = tracecmd_get_show_data_func(handle);
823 	const char *tfmt = time_format(handle, TIME_FMT_NORMAL);
824 	const char *cfmt = latency_format ? "%8.8s-%-5d %3d" : "%16s-%-5d [%03d]";
825 	struct tep_handle *pevent;
826 	struct tep_event *event;
827 	struct trace_seq s;
828 	int cpu = record->cpu;
829 	bool use_trace_clock;
830 	static unsigned long long last_ts;
831 	unsigned long long diff_ts;
832 	unsigned long page_size;
833 	char buf[50];
834 
835 	page_size = tracecmd_page_size(handle);
836 
837 	test_save(record, cpu);
838 
839 	if (func) {
840 		func(handle, record);
841 		return;
842 	}
843 
844 	pevent = tracecmd_get_tep(handle);
845 	event = tep_find_event_by_record(pevent, record);
846 	use_trace_clock = tracecmd_get_use_trace_clock(handle);
847 
848 	trace_seq_init(&s);
849 	if (record->missed_events > 0)
850 		trace_seq_printf(&s, "CPU:%d [%lld EVENTS DROPPED]\n",
851 				 cpu, record->missed_events);
852 	else if (record->missed_events < 0)
853 		trace_seq_printf(&s, "CPU:%d [EVENTS DROPPED]\n", cpu);
854 	if (buffer_breaks || tracecmd_get_debug()) {
855 		if (tracecmd_record_at_buffer_start(handle, record)) {
856 			trace_seq_printf(&s, "CPU:%d [SUBBUFFER START]", cpu);
857 			if (tracecmd_get_debug())
858 				trace_seq_printf(&s, " [%lld:0x%llx]",
859 						 tracecmd_page_ts(handle, record),
860 						 record->offset & ~(page_size - 1));
861 			trace_seq_putc(&s, '\n');
862 		}
863 	}
864 
865 	tep_print_event(pevent, &s, record, cfmt,
866 			TEP_PRINT_COMM,
867 			TEP_PRINT_PID,
868 			TEP_PRINT_CPU);
869 
870 	if (latency_format) {
871 		if (raw_format)
872 			trace_seq_printf(&s, "-0x%x",
873 					 tep_data_flags(pevent, record));
874 		else
875 			tep_print_event(pevent, &s, record, "%s",
876 					TEP_PRINT_LATENCY);
877 	}
878 
879 	tep_print_event(pevent, &s, record, tfmt, TEP_PRINT_TIME);
880 
881 	if (tsdiff) {
882 		unsigned long long rec_ts = record->ts;
883 
884 		buf[0] = 0;
885 		if (use_trace_clock && !tep_test_flag(pevent, TEP_NSEC_OUTPUT))
886 			rec_ts = (rec_ts + 500) / 1000;
887 		if (last_ts) {
888 			diff_ts = rec_ts - last_ts;
889 			snprintf(buf, 50, "(+%lld)", diff_ts);
890 			buf[49] = 0;
891 		}
892 		last_ts = rec_ts;
893 		trace_seq_printf(&s, " %-8s", buf);
894 	}
895 
896 	print_event_name(&s, event);
897 	tep_print_event(pevent, &s, record, "%s", format_type);
898 
899 	if (s.len && *(s.buffer + s.len - 1) == '\n')
900 		s.len--;
901 	if (tracecmd_get_debug()) {
902 		struct kbuffer *kbuf;
903 		struct kbuffer_raw_info info;
904 		void *page;
905 		void *offset;
906 
907 		trace_seq_printf(&s, " [%d:0x%llx:%d]",
908 				 tracecmd_record_ts_delta(handle, record),
909 				 record->offset & (page_size - 1), record->size);
910 		kbuf = tracecmd_record_kbuf(handle, record);
911 		page = tracecmd_record_page(handle, record);
912 		offset = tracecmd_record_offset(handle, record);
913 
914 		if (kbuf && page && offset) {
915 			struct kbuffer_raw_info *pi = &info;
916 
917 			/* We need to get the record raw data to get next */
918 			pi->next = offset;
919 			pi = kbuffer_raw_get(kbuf, page, pi);
920 			while ((pi = kbuffer_raw_get(kbuf, page, pi))) {
921 				if (pi->type < KBUFFER_TYPE_PADDING)
922 					break;
923 				switch (pi->type) {
924 				case KBUFFER_TYPE_PADDING:
925 					trace_seq_printf(&s, "\n PADDING: ");
926 					break;
927 				case KBUFFER_TYPE_TIME_EXTEND:
928 					trace_seq_printf(&s, "\n TIME EXTEND: ");
929 					break;
930 				case KBUFFER_TYPE_TIME_STAMP:
931 					trace_seq_printf(&s, "\n TIME STAMP: ");
932 					break;
933 				}
934 				if (pi->type == KBUFFER_TYPE_TIME_STAMP)
935 					trace_seq_printf(&s, "timestamp:%lld length:%d",
936 							 pi->delta,
937 							 pi->length);
938 				else
939 					trace_seq_printf(&s, "delta:%lld length:%d",
940 							 pi->delta,
941 							 pi->length);
942 			}
943 		}
944 	}
945 
946 	trace_seq_do_printf(&s);
947 	trace_seq_destroy(&s);
948 
949 	process_wakeup(pevent, record);
950 
951 	printf("\n");
952 }
953 
read_latency(struct tracecmd_input * handle)954 static void read_latency(struct tracecmd_input *handle)
955 {
956 	char *buf = NULL;
957 	size_t size = 0;
958 	int r;
959 
960 	do {
961 		r = tracecmd_latency_data_read(handle, &buf, &size);
962 		if (r > 0)
963 			printf("%.*s", r, buf);
964 	} while (r > 0);
965 
966 	printf("\n");
967 	free(buf);
968 }
969 
970 static int
test_filters(struct tep_handle * pevent,struct filter * event_filters,struct tep_record * record,int neg)971 test_filters(struct tep_handle *pevent, struct filter *event_filters,
972 	     struct tep_record *record, int neg)
973 {
974 	int found = 0;
975 	int ret = FILTER_NONE;
976 	int flags;
977 
978 	if (no_irqs || no_softirqs) {
979 		flags = tep_data_flags(pevent, record);
980 		if (no_irqs && (flags & TRACE_FLAG_HARDIRQ))
981 			return FILTER_MISS;
982 		if (no_softirqs && (flags & TRACE_FLAG_SOFTIRQ))
983 			return FILTER_MISS;
984 	}
985 
986 	while (event_filters) {
987 		ret = tep_filter_match(event_filters->filter, record);
988 		switch (ret) {
989 			case FILTER_NONE:
990 			case FILTER_MATCH:
991 				found = 1;
992 		}
993 		/* We need to test all negative filters */
994 		if (!neg && found)
995 			break;
996 		event_filters = event_filters->next;
997 	}
998 
999 	return ret;
1000 }
1001 
1002 struct stack_info_cpu {
1003 	int			cpu;
1004 	int			last_printed;
1005 };
1006 
1007 struct stack_info {
1008 	struct stack_info	*next;
1009 	struct handle_list	*handles;
1010 	struct stack_info_cpu	*cpus;
1011 	int			stacktrace_id;
1012 	int			nr_cpus;
1013 };
1014 
1015 static int
test_stacktrace(struct handle_list * handles,struct tep_record * record,int last_printed)1016 test_stacktrace(struct handle_list *handles, struct tep_record *record,
1017 		int last_printed)
1018 {
1019 	static struct stack_info *infos;
1020 	struct stack_info *info;
1021 	struct stack_info_cpu *cpu_info;
1022 	struct handle_list *h;
1023 	struct tracecmd_input *handle;
1024 	struct tep_handle *pevent;
1025 	struct tep_event *event;
1026 	static int init;
1027 	int ret;
1028 	int id;
1029 
1030 	if (!init) {
1031 		init = 1;
1032 
1033 		list_for_each_entry(h, &handle_list, list) {
1034 			info = malloc(sizeof(*info));
1035 			if (!info)
1036 				die("Failed to allocate handle");
1037 			info->handles = h;
1038 			info->nr_cpus = tracecmd_cpus(h->handle);
1039 
1040 			info->cpus = malloc(sizeof(*info->cpus) * info->nr_cpus);
1041 			if (!info->cpus)
1042 				die("Failed to allocate for %d cpus", info->nr_cpus);
1043 			memset(info->cpus, 0, sizeof(*info->cpus));
1044 
1045 			pevent = tracecmd_get_tep(h->handle);
1046 			event = tep_find_event_by_name(pevent, "ftrace",
1047 						       "kernel_stack");
1048 			if (event)
1049 				info->stacktrace_id = event->id;
1050 			else
1051 				info->stacktrace_id = 0;
1052 
1053 			info->next = infos;
1054 			infos = info;
1055 		}
1056 
1057 
1058 	}
1059 
1060 	handle = handles->handle;
1061 	pevent = tracecmd_get_tep(handle);
1062 
1063 	for (info = infos; info; info = info->next)
1064 		if (info->handles == handles)
1065 			break;
1066 
1067 	if (!info->stacktrace_id)
1068 		return 0;
1069 
1070 	cpu_info = &info->cpus[record->cpu];
1071 
1072 	id = tep_data_type(pevent, record);
1073 
1074 	/*
1075 	 * Print the stack trace if the previous event was printed.
1076 	 * But do not print the stack trace if it is explicitly
1077 	 * being filtered out.
1078 	 */
1079 	if (id == info->stacktrace_id) {
1080 		ret = test_filters(pevent, handles->event_filter_out, record, 1);
1081 		if (ret != FILTER_MATCH)
1082 			return cpu_info->last_printed;
1083 		return 0;
1084 	}
1085 
1086 	cpu_info->last_printed = last_printed;
1087 	return 0;
1088 }
1089 
get_next_record(struct handle_list * handles)1090 static struct tep_record *get_next_record(struct handle_list *handles)
1091 {
1092 	struct tep_record *record;
1093 	struct tep_handle *pevent;
1094 	int found = 0;
1095 	int cpu;
1096 	int ret;
1097 
1098 	if (handles->record)
1099 		return handles->record;
1100 
1101 	if (handles->done)
1102 		return NULL;
1103 
1104 	pevent = tracecmd_get_tep(handles->handle);
1105 
1106 	do {
1107 		if (filter_cpus) {
1108 			long long last_stamp = -1;
1109 			struct tep_record *precord;
1110 			int first_record = 1;
1111 			int next_cpu = -1;
1112 			int i;
1113 
1114 			for (i = 0; (cpu = filter_cpus[i]) >= 0; i++) {
1115 				precord = tracecmd_peek_data(handles->handle, cpu);
1116 				if (precord &&
1117 				    (first_record || precord->ts < last_stamp)) {
1118 					next_cpu = cpu;
1119 					last_stamp = precord->ts;
1120 					first_record = 0;
1121 				}
1122 			}
1123 			if (!first_record)
1124 				record = tracecmd_read_data(handles->handle, next_cpu);
1125 			else
1126 				record = NULL;
1127 		} else
1128 			record = tracecmd_read_next_data(handles->handle, &cpu);
1129 
1130 		if (record) {
1131 			ret = test_filters(pevent, handles->event_filters, record, 0);
1132 			switch (ret) {
1133 			case FILTER_NOEXIST:
1134 				/* Stack traces may still filter this */
1135 				if (stacktrace_id &&
1136 				    test_stacktrace(handles, record, 0))
1137 					found = 1;
1138 				else
1139 					tracecmd_free_record(record);
1140 				break;
1141 			case FILTER_NONE:
1142 			case FILTER_MATCH:
1143 				/* Test the negative filters (-v) */
1144 				ret = test_filters(pevent, handles->event_filter_out,
1145 						   record, 1);
1146 				if (ret != FILTER_MATCH) {
1147 					found = 1;
1148 					break;
1149 				}
1150 				/* fall through */
1151 			default:
1152 				tracecmd_free_record(record);
1153 			}
1154 		}
1155 	} while (record && !found);
1156 
1157 	if (record && stacktrace_id)
1158 		test_stacktrace(handles, record, 1);
1159 
1160 	handles->record = record;
1161 	if (!record)
1162 		handles->done = 1;
1163 
1164 	return record;
1165 }
1166 
free_handle_record(struct handle_list * handles)1167 static void free_handle_record(struct handle_list *handles)
1168 {
1169 	if (!handles->record)
1170 		return;
1171 
1172 	tracecmd_free_record(handles->record);
1173 	handles->record = NULL;
1174 }
1175 
print_handle_file(struct handle_list * handles)1176 static void print_handle_file(struct handle_list *handles)
1177 {
1178 	/* Only print file names if more than one file is read */
1179 	if (!multi_inputs && !instances)
1180 		return;
1181 	if (handles->file && *handles->file != '\0')
1182 		printf("%*s: ", max_file_size, handles->file);
1183 	else
1184 		printf("%*s  ", max_file_size, "");
1185 }
1186 
free_filters(struct filter * event_filter)1187 static void free_filters(struct filter *event_filter)
1188 {
1189 	struct filter *filter;
1190 
1191 	while (event_filter) {
1192 		filter = event_filter;
1193 		event_filter = filter->next;
1194 
1195 		tep_filter_free(filter->filter);
1196 		free(filter);
1197 	}
1198 }
1199 
1200 enum output_type {
1201 	OUTPUT_NORMAL,
1202 	OUTPUT_STAT_ONLY,
1203 	OUTPUT_UNAME_ONLY,
1204 	OUTPUT_VERSION_ONLY,
1205 };
1206 
read_data_info(struct list_head * handle_list,enum output_type otype,int global,int align_ts)1207 static void read_data_info(struct list_head *handle_list, enum output_type otype,
1208 			   int global, int align_ts)
1209 {
1210 	unsigned long long ts, first_ts;
1211 	struct handle_list *handles;
1212 	struct handle_list *last_handle;
1213 	struct tep_record *record;
1214 	struct tep_record *last_record;
1215 	struct tep_handle *pevent;
1216 	struct tep_event *event;
1217 	int first = 1;
1218 	int ret;
1219 
1220 	list_for_each_entry(handles, handle_list, list) {
1221 		int cpus;
1222 
1223 		if (!tracecmd_is_buffer_instance(handles->handle)) {
1224 			ret = tracecmd_init_data(handles->handle);
1225 			if (ret < 0)
1226 				die("failed to init data");
1227 		}
1228 		cpus = tracecmd_cpus(handles->handle);
1229 		handles->cpus = cpus;
1230 		handles->last_timestamp = calloc(cpus, sizeof(*handles->last_timestamp));
1231 		if (!handles->last_timestamp)
1232 			die("allocating timestamps");
1233 
1234 		/* Don't process instances that we added here */
1235 		if (tracecmd_is_buffer_instance(handles->handle))
1236 			continue;
1237 
1238 		if (align_ts) {
1239 			ts = tracecmd_get_first_ts(handles->handle);
1240 			if (first || first_ts > ts)
1241 				first_ts = ts;
1242 			first = 0;
1243 		}
1244 		print_handle_file(handles);
1245 		printf("cpus=%d\n", cpus);
1246 
1247 		/* Latency trace is just all ASCII */
1248 		if (ret > 0) {
1249 			if (multi_inputs)
1250 				die("latency traces do not work with multiple inputs");
1251 			read_latency(handles->handle);
1252 			return;
1253 		}
1254 
1255 		switch (otype) {
1256 		case OUTPUT_NORMAL:
1257 			break;
1258 		case OUTPUT_STAT_ONLY:
1259 			printf("\nKernel buffer statistics:\n"
1260 			       "  Note: \"entries\" are the entries left in the kernel ring buffer and are not\n"
1261 			       "        recorded in the trace data. They should all be zero.\n\n");
1262 			tracecmd_print_stats(handles->handle);
1263 			continue;
1264 		case OUTPUT_UNAME_ONLY:
1265 			tracecmd_print_uname(handles->handle);
1266 		case OUTPUT_VERSION_ONLY:
1267 			tracecmd_print_version(handles->handle);
1268 			continue;
1269 		}
1270 
1271 		/* Find the kernel_stacktrace if available */
1272 		pevent = tracecmd_get_tep(handles->handle);
1273 		event = tep_find_event_by_name(pevent, "ftrace", "kernel_stack");
1274 		if (event)
1275 			stacktrace_id = event->id;
1276 
1277 		init_wakeup(handles->handle);
1278 		if (last_hook)
1279 			last_hook->next = tracecmd_hooks(handles->handle);
1280 		else
1281 			hooks = tracecmd_hooks(handles->handle);
1282 		if (profile)
1283 			trace_init_profile(handles->handle, hooks, global);
1284 
1285 		process_filters(handles);
1286 
1287 		/* If this file has buffer instances, get the handles for them */
1288 		instances = tracecmd_buffer_instances(handles->handle);
1289 		if (instances) {
1290 			struct tracecmd_input *new_handle;
1291 			const char *name;
1292 			int i;
1293 
1294 			for (i = 0; i < instances; i++) {
1295 				name = tracecmd_buffer_instance_name(handles->handle, i);
1296 				if (!name)
1297 					die("error in reading buffer instance");
1298 				new_handle = tracecmd_buffer_instance_handle(handles->handle, i);
1299 				if (!new_handle) {
1300 					warning("could not retrieve handle %s", name);
1301 					continue;
1302 				}
1303 				add_handle(new_handle, name);
1304 			}
1305 		}
1306 	}
1307 
1308 	if (otype != OUTPUT_NORMAL)
1309 		return;
1310 
1311 	if (align_ts) {
1312 		list_for_each_entry(handles, handle_list, list) {
1313 			tracecmd_add_ts_offset(handles->handle, -first_ts);
1314 		}
1315 	}
1316 
1317 	do {
1318 		last_handle = NULL;
1319 		last_record = NULL;
1320 
1321 		list_for_each_entry(handles, handle_list, list) {
1322 			record = get_next_record(handles);
1323 			if (!record)
1324 				continue;
1325 			if (!last_record ||
1326 			    (record && record->ts < last_record->ts)) {
1327 				last_record = record;
1328 				last_handle = handles;
1329 			}
1330 		}
1331 		if (last_record) {
1332 			int cpu = last_record->cpu;
1333 			if (cpu >= last_handle->cpus)
1334 				die("cpu %d greater than %d\n", cpu, last_handle->cpus);
1335 			if (tscheck &&
1336 			    last_handle->last_timestamp[cpu] > last_record->ts) {
1337 				errno = 0;
1338 				warning("WARNING: Record on cpu %d went backwards: %lld to %lld delta: -%lld\n",
1339 					cpu, last_handle->last_timestamp[cpu],
1340 					last_record->ts,
1341 					last_handle->last_timestamp[cpu] - last_record->ts);
1342 			}
1343 			last_handle->last_timestamp[cpu] = last_record->ts;
1344 			print_handle_file(last_handle);
1345 			trace_show_data(last_handle->handle, last_record);
1346 			free_handle_record(last_handle);
1347 		}
1348 	} while (last_record);
1349 
1350 	if (profile)
1351 		do_trace_profile();
1352 
1353 	list_for_each_entry(handles, handle_list, list) {
1354 		free_filters(handles->event_filters);
1355 		free_filters(handles->event_filter_out);
1356 		free(handles->last_timestamp);
1357 
1358 		show_test(handles->handle);
1359 	}
1360 }
1361 
read_trace_header(const char * file,int flags)1362 struct tracecmd_input *read_trace_header(const char *file, int flags)
1363 {
1364 	input_fd = open(file, O_RDONLY);
1365 	if (input_fd < 0)
1366 		die("opening '%s'\n", file);
1367 
1368 	return tracecmd_alloc_fd(input_fd, flags);
1369 }
1370 
sig_end(int sig)1371 static void sig_end(int sig)
1372 {
1373 	struct handle_list *handles;
1374 
1375 	fprintf(stderr, "trace-cmd: Received SIGINT\n");
1376 
1377 	list_for_each_entry(handles, &handle_list, list) {
1378 		tracecmd_close(handles->handle);
1379 	}
1380 
1381 	exit(0);
1382 }
1383 
skip_space_and_test_digit(const char * p,const char * cpu_str)1384 static const char *skip_space_and_test_digit(const char *p, const char *cpu_str)
1385 {
1386 	while (isspace(*p))
1387 		p++;
1388 	if (!isdigit(*p))
1389 		die("invalid character '%c' in cpu string '%s'",
1390 		    *p, cpu_str);
1391 	return p;
1392 }
1393 
__add_cpu(int cpu)1394 static void __add_cpu(int cpu)
1395 {
1396 	filter_cpus = tracecmd_add_id(filter_cpus, cpu, nr_filter_cpus++);
1397 }
1398 
parse_cpulist(const char * cpu_str)1399 static void parse_cpulist(const char *cpu_str)
1400 {
1401 	unsigned a, b;
1402 	const char *s = cpu_str;
1403 
1404 	do {
1405 		s = skip_space_and_test_digit(s, cpu_str);
1406 		b = a = strtoul(s, (char **)&s, 10);
1407 		if (*s == '-') {
1408 			s = skip_space_and_test_digit(s + 1, cpu_str);
1409 			b = strtoul(s, (char **)&s, 10);
1410 		}
1411 		if (!(a <= b))
1412 			die("range of cpu numbers must be lower to greater");
1413 		while (a <= b) {
1414 			__add_cpu(a);
1415 			a++;
1416 		}
1417 		if (*s == ',' || *s == ':')
1418 			s++;
1419 	} while (*s != '\0');
1420 }
1421 
read_file_fd(int fd,char * dst,int len)1422 static void read_file_fd(int fd, char *dst, int len)
1423 {
1424 	size_t size = 0;
1425 	int r;
1426 
1427 	do {
1428 		r = read(fd, dst+size, len);
1429 		if (r > 0) {
1430 			size += r;
1431 			len -= r;
1432 		}
1433 	} while (r > 0);
1434 }
1435 
add_functions(struct tep_handle * pevent,const char * file)1436 static void add_functions(struct tep_handle *pevent, const char *file)
1437 {
1438 	struct stat st;
1439 	char *buf;
1440 	int ret;
1441 	int fd;
1442 
1443 	fd = open(file, O_RDONLY);
1444 	if (fd < 0)
1445 		die("Can't read file %s", file);
1446 
1447 	ret = fstat(fd, &st);
1448 	if (ret < 0)
1449 		die("Can't stat file %s", file);
1450 
1451 	buf = malloc(st.st_size + 1);
1452 	if (!buf)
1453 		die("Failed to allocate for function buffer");
1454 	read_file_fd(fd, buf, st.st_size);
1455 	buf[st.st_size] = '\0';
1456 	close(fd);
1457 	tep_parse_kallsyms(pevent, buf);
1458 	free(buf);
1459 }
1460 
process_plugin_option(char * option)1461 static void process_plugin_option(char *option)
1462 {
1463 	char *name = option;
1464 	char *val = NULL;
1465 	char *p;
1466 
1467 	if ((p = strstr(name, "="))) {
1468 		*p = '\0';
1469 		val = p+1;
1470 	}
1471 	tep_plugin_add_option(name, val);
1472 }
1473 
set_event_flags(struct tep_handle * pevent,struct event_str * list,unsigned int flag)1474 static void set_event_flags(struct tep_handle *pevent, struct event_str *list,
1475 			    unsigned int flag)
1476 {
1477 	struct tep_event **events;
1478 	struct tep_event *event;
1479 	struct event_str *str;
1480 	regex_t regex;
1481 	int ret;
1482 	int i;
1483 
1484 	if (!list)
1485 		return;
1486 
1487 	events = tep_list_events(pevent, 0);
1488 
1489 	for (str = list; str; str = str->next) {
1490 		char *match;
1491 
1492 		match = malloc(strlen(str->event) + 3);
1493 		if (!match)
1494 			die("Failed to allocate for match string '%s'", str->event);
1495 		sprintf(match, "^%s$", str->event);
1496 
1497 		ret = regcomp(&regex, match, REG_ICASE|REG_NOSUB);
1498 		if (ret < 0)
1499 			die("Can't parse '%s'", str->event);
1500 		free(match);
1501 		for (i = 0; events[i]; i++) {
1502 			event = events[i];
1503 			if (!regexec(&regex, event->name, 0, NULL, 0) ||
1504 			    !regexec(&regex, event->system, 0, NULL, 0))
1505 				event->flags |= flag;
1506 		}
1507 	}
1508 }
1509 
add_hook(const char * arg)1510 static void add_hook(const char *arg)
1511 {
1512 	struct hook_list *hook;
1513 
1514 	hook = tracecmd_create_event_hook(arg);
1515 
1516 	hook->next = hooks;
1517 	hooks = hook;
1518 	if (!last_hook)
1519 		last_hook = hook;
1520 }
1521 
1522 enum {
1523 	OPT_verbose	= 234,
1524 	OPT_align_ts	= 235,
1525 	OPT_raw_ts	= 236,
1526 	OPT_version	= 237,
1527 	OPT_tscheck	= 238,
1528 	OPT_tsdiff	= 239,
1529 	OPT_ts2secs	= 240,
1530 	OPT_tsoffset	= 241,
1531 	OPT_bycomm	= 242,
1532 	OPT_debug	= 243,
1533 	OPT_uname	= 244,
1534 	OPT_profile	= 245,
1535 	OPT_event	= 246,
1536 	OPT_comm	= 247,
1537 	OPT_boundary	= 248,
1538 	OPT_stat	= 249,
1539 	OPT_pid		= 250,
1540 	OPT_nodate	= 251,
1541 	OPT_check_event_parsing	= 252,
1542 	OPT_kallsyms	= 253,
1543 	OPT_events	= 254,
1544 	OPT_cpu		= 255,
1545 	OPT_cpus	= 256,
1546 };
1547 
trace_report(int argc,char ** argv)1548 void trace_report (int argc, char **argv)
1549 {
1550 	struct tracecmd_input *handle;
1551 	struct tep_handle *pevent;
1552 	struct event_str *raw_events = NULL;
1553 	struct event_str *nohandler_events = NULL;
1554 	struct event_str **raw_ptr = &raw_events;
1555 	struct event_str **nohandler_ptr = &nohandler_events;
1556 	const char *functions = NULL;
1557 	const char *print_event = NULL;
1558 	struct input_files *inputs;
1559 	struct handle_list *handles;
1560 	enum output_type otype;
1561 	long long tsoffset = 0;
1562 	unsigned long long ts2secs = 0;
1563 	unsigned long long ts2sc;
1564 	int open_flags = 0;
1565 	int show_stat = 0;
1566 	int show_funcs = 0;
1567 	int show_endian = 0;
1568 	int show_page_size = 0;
1569 	int show_printk = 0;
1570 	int show_uname = 0;
1571 	int show_version = 0;
1572 	int show_events = 0;
1573 	int show_cpus = 0;
1574 	int print_events = 0;
1575 	int nanosec = 0;
1576 	int no_date = 0;
1577 	int raw_ts = 0;
1578 	int align_ts = 0;
1579 	int global = 0;
1580 	int neg = 0;
1581 	int ret = 0;
1582 	int check_event_parsing = 0;
1583 	int c;
1584 
1585 	list_head_init(&handle_list);
1586 	list_head_init(&input_files);
1587 
1588 	if (argc < 2)
1589 		usage(argv);
1590 
1591 	if (strcmp(argv[1], "report") != 0)
1592 		usage(argv);
1593 
1594 	signal(SIGINT, sig_end);
1595 
1596 	for (;;) {
1597 		int option_index = 0;
1598 		static struct option long_options[] = {
1599 			{"cpu", required_argument, NULL, OPT_cpu},
1600 			{"cpus", no_argument, NULL, OPT_cpus},
1601 			{"events", no_argument, NULL, OPT_events},
1602 			{"event", required_argument, NULL, OPT_event},
1603 			{"filter-test", no_argument, NULL, 'T'},
1604 			{"kallsyms", required_argument, NULL, OPT_kallsyms},
1605 			{"pid", required_argument, NULL, OPT_pid},
1606 			{"comm", required_argument, NULL, OPT_comm},
1607 			{"check-events", no_argument, NULL,
1608 				OPT_check_event_parsing},
1609 			{"nodate", no_argument, NULL, OPT_nodate},
1610 			{"stat", no_argument, NULL, OPT_stat},
1611 			{"boundary", no_argument, NULL, OPT_boundary},
1612 			{"debug", no_argument, NULL, OPT_debug},
1613 			{"profile", no_argument, NULL, OPT_profile},
1614 			{"uname", no_argument, NULL, OPT_uname},
1615 			{"version", no_argument, NULL, OPT_version},
1616 			{"by-comm", no_argument, NULL, OPT_bycomm},
1617 			{"ts-offset", required_argument, NULL, OPT_tsoffset},
1618 			{"ts2secs", required_argument, NULL, OPT_ts2secs},
1619 			{"ts-diff", no_argument, NULL, OPT_tsdiff},
1620 			{"ts-check", no_argument, NULL, OPT_tscheck},
1621 			{"raw-ts", no_argument, NULL, OPT_raw_ts},
1622 			{"align-ts", no_argument, NULL, OPT_align_ts},
1623 			{"verbose", optional_argument, NULL, OPT_verbose},
1624 			{"help", no_argument, NULL, '?'},
1625 			{NULL, 0, NULL, 0}
1626 		};
1627 
1628 		c = getopt_long (argc-1, argv+1, "+hSIi:H:feGpRr:tPNn:LlEwF:V::vTqO:",
1629 			long_options, &option_index);
1630 		if (c == -1)
1631 			break;
1632 		switch (c) {
1633 		case 'h':
1634 			usage(argv);
1635 			break;
1636 		case 'i':
1637 			if (input_file) {
1638 				if (!multi_inputs) {
1639 					add_input(input_file);
1640 					if (tsoffset)
1641 						last_input_file->tsoffset = tsoffset;
1642 				}
1643 				multi_inputs++;
1644 				add_input(optarg);
1645 			} else
1646 				input_file = optarg;
1647 			break;
1648 		case 'F':
1649 			add_filter(optarg, neg);
1650 			break;
1651 		case 'H':
1652 			add_hook(optarg);
1653 			break;
1654 		case 'T':
1655 			test_filters_mode = 1;
1656 			break;
1657 		case 'f':
1658 			show_funcs = 1;
1659 			break;
1660 		case 'I':
1661 			no_irqs = 1;
1662 			break;
1663 		case 'S':
1664 			no_softirqs = 1;
1665 			break;
1666 		case 'P':
1667 			show_printk = 1;
1668 			break;
1669 		case 'L':
1670 			open_flags |= TRACECMD_FL_LOAD_NO_SYSTEM_PLUGINS;
1671 			break;
1672 		case 'N':
1673 			open_flags |= TRACECMD_FL_LOAD_NO_PLUGINS;
1674 			break;
1675 		case 'n':
1676 			*nohandler_ptr = malloc(sizeof(struct event_str));
1677 			if (!*nohandler_ptr)
1678 				die("Failed to allocate for '-n %s'", optarg);
1679 			(*nohandler_ptr)->event = optarg;
1680 			(*nohandler_ptr)->next = NULL;
1681 			nohandler_ptr = &(*nohandler_ptr)->next;
1682 			break;
1683 		case 'e':
1684 			show_endian = 1;
1685 			break;
1686 		case 'p':
1687 			show_page_size = 1;
1688 			break;
1689 		case 'E':
1690 			show_events = 1;
1691 			break;
1692 		case 'G':
1693 			global = 1;
1694 			break;
1695 		case 'R':
1696 			raw_format = true;
1697 			break;
1698 		case 'r':
1699 			*raw_ptr = malloc(sizeof(struct event_str));
1700 			if (!*raw_ptr)
1701 				die("Failed to allocate '-r %s'", optarg);
1702 			(*raw_ptr)->event = optarg;
1703 			(*raw_ptr)->next = NULL;
1704 			raw_ptr = &(*raw_ptr)->next;
1705 			break;
1706 		case 't':
1707 			nanosec = 1;
1708 			break;
1709 		case 'w':
1710 			show_wakeup = 1;
1711 			break;
1712 		case 'l':
1713 			latency_format = 1;
1714 			break;
1715 		case 'O':
1716 			process_plugin_option(optarg);
1717 			break;
1718 		case 'v':
1719 			if (neg)
1720 				die("Only 1 -v can be used");
1721 			neg = 1;
1722 			break;
1723 		case 'q':
1724 			silence_warnings = 1;
1725 			tracecmd_set_loglevel(TEP_LOG_NONE);
1726 			break;
1727 		case OPT_cpu:
1728 			parse_cpulist(optarg);
1729 			break;
1730 		case OPT_cpus:
1731 			show_cpus = 1;
1732 			break;
1733 		case OPT_events:
1734 			print_events = 1;
1735 			break;
1736 		case OPT_event:
1737 			print_event = optarg;
1738 			break;
1739 		case OPT_kallsyms:
1740 			functions = optarg;
1741 			break;
1742 		case OPT_pid:
1743 			add_pid_filter(optarg);
1744 			break;
1745 		case OPT_comm:
1746 			add_comm_filter(optarg);
1747 			break;
1748 		case OPT_check_event_parsing:
1749 			check_event_parsing = 1;
1750 			break;
1751 		case OPT_nodate:
1752 			no_date = 1;
1753 			break;
1754 		case OPT_stat:
1755 			show_stat = 1;
1756 			break;
1757 		case OPT_boundary:
1758 			/* Debug to look at buffer breaks */
1759 			buffer_breaks = 1;
1760 			break;
1761 		case OPT_debug:
1762 			buffer_breaks = 1;
1763 			tracecmd_set_debug(true);
1764 			break;
1765 		case OPT_profile:
1766 			profile = 1;
1767 			break;
1768 		case OPT_uname:
1769 			show_uname = 1;
1770 			break;
1771 		case OPT_version:
1772 			show_version = 1;
1773 			break;
1774 		case OPT_bycomm:
1775 			trace_profile_set_merge_like_comms();
1776 			break;
1777 		case OPT_ts2secs:
1778 			ts2sc = atoll(optarg);
1779 			if (multi_inputs)
1780 				last_input_file->ts2secs = ts2sc;
1781 			else
1782 				ts2secs = ts2sc;
1783 			break;
1784 		case OPT_tsoffset:
1785 			tsoffset = atoll(optarg);
1786 			if (multi_inputs)
1787 				last_input_file->tsoffset = tsoffset;
1788 			if (!input_file)
1789 				die("--ts-offset must come after -i");
1790 			break;
1791 		case OPT_tsdiff:
1792 			tsdiff = 1;
1793 			break;
1794 		case OPT_tscheck:
1795 			tscheck = 1;
1796 			break;
1797 		case OPT_raw_ts:
1798 			raw_ts = 1;
1799 			break;
1800 		case OPT_align_ts:
1801 			align_ts = 1;
1802 			break;
1803 		case 'V':
1804 		case OPT_verbose:
1805 			show_status = 1;
1806 			if (trace_set_verbose(optarg) < 0)
1807 				die("invalid verbose level %s", optarg);
1808 			break;
1809 		default:
1810 			usage(argv);
1811 		}
1812 	}
1813 
1814 	if ((argc - optind) >= 2) {
1815 		if (input_file)
1816 			usage(argv);
1817 		input_file = argv[optind + 1];
1818 	}
1819 
1820 	if (!input_file)
1821 		input_file = default_input_file;
1822 
1823 	if (!multi_inputs) {
1824 		add_input(input_file);
1825 		if (tsoffset)
1826 			last_input_file->tsoffset = tsoffset;
1827 	} else if (show_wakeup)
1828 		die("Wakeup tracing can only be done on a single input file");
1829 
1830 	list_for_each_entry(inputs, &input_files, list) {
1831 		handle = read_trace_header(inputs->file, open_flags);
1832 		if (!handle)
1833 			die("error reading header for %s", inputs->file);
1834 
1835 		/* If used with instances, top instance will have no tag */
1836 		add_handle(handle, multi_inputs ? inputs->file : NULL);
1837 
1838 		if (no_date)
1839 			tracecmd_set_flag(handle, TRACECMD_FL_IGNORE_DATE);
1840 		if (raw_ts)
1841 			tracecmd_set_flag(handle, TRACECMD_FL_RAW_TS);
1842 		page_size = tracecmd_page_size(handle);
1843 
1844 		if (show_page_size) {
1845 			printf("file page size is %d, and host page size is %d\n",
1846 			       page_size,
1847 			       getpagesize());
1848 			return;
1849 		}
1850 
1851 		if (inputs->tsoffset)
1852 			tracecmd_set_ts_offset(handle, inputs->tsoffset);
1853 
1854 		if (inputs->ts2secs)
1855 			tracecmd_set_ts2secs(handle, inputs->ts2secs);
1856 		else if (ts2secs)
1857 			tracecmd_set_ts2secs(handle, ts2secs);
1858 
1859 		pevent = tracecmd_get_tep(handle);
1860 
1861 		if (nanosec)
1862 			tep_set_flag(pevent, TEP_NSEC_OUTPUT);
1863 
1864 		if (raw_format)
1865 			format_type = TEP_PRINT_INFO_RAW;
1866 
1867 		if (test_filters_mode)
1868 			tep_set_test_filters(pevent, 1);
1869 
1870 		if (functions)
1871 			add_functions(pevent, functions);
1872 
1873 		if (show_endian) {
1874 			printf("file is %s endian and host is %s endian\n",
1875 				tep_is_file_bigendian(pevent) ? "big" : "little",
1876 				tep_is_local_bigendian(pevent) ? "big" : "little");
1877 			return;
1878 		}
1879 
1880 		if (print_events) {
1881 			tracecmd_print_events(handle, NULL);
1882 			return;
1883 		}
1884 
1885 		if (print_event) {
1886 			tracecmd_print_events(handle, print_event);
1887 			return;
1888 		}
1889 
1890 		ret = tracecmd_read_headers(handle, 0);
1891 		if (check_event_parsing) {
1892 			if (ret || tracecmd_get_parsing_failures(handle))
1893 				exit(EINVAL);
1894 			else
1895 				exit(0);
1896 		} else {
1897 			if (ret)
1898 				return;
1899 		}
1900 
1901 		if (show_funcs) {
1902 			tep_print_funcs(pevent);
1903 			return;
1904 		}
1905 		if (show_printk) {
1906 			tep_print_printk(pevent);
1907 			return;
1908 		}
1909 
1910 		if (show_events) {
1911 			struct tep_event **events;
1912 			struct tep_event *event;
1913 			int i;
1914 
1915 			events = tep_list_events(pevent, TEP_EVENT_SORT_SYSTEM);
1916 			for (i = 0; events[i]; i++) {
1917 				event = events[i];
1918 				if (event->system)
1919 					printf("%s:", event->system);
1920 				printf("%s\n", event->name);
1921 			}
1922 			return;
1923 		}
1924 
1925 		if (show_cpus) {
1926 			int cpus;
1927 			int ret;
1928 			int i;
1929 
1930 			if (!tracecmd_is_buffer_instance(handle)) {
1931 				ret = tracecmd_init_data(handle);
1932 				if (ret < 0)
1933 					die("failed to init data");
1934 			}
1935 			cpus = tracecmd_cpus(handle);
1936 			printf("List of CPUs in %s with data:\n", inputs->file);
1937 			for (i = 0; i < cpus; i++) {
1938 				if (tracecmd_read_cpu_first(handle, i))
1939 					printf("  %d\n", i);
1940 			}
1941 			continue;
1942 		}
1943 
1944 		set_event_flags(pevent, nohandler_events, TEP_EVENT_FL_NOHANDLE);
1945 		set_event_flags(pevent, raw_events, TEP_EVENT_FL_PRINTRAW);
1946 	}
1947 
1948 	if (show_cpus)
1949 		return;
1950 
1951 	otype = OUTPUT_NORMAL;
1952 
1953 	if (tracecmd_get_flags(handle) & TRACECMD_FL_RAW_TS) {
1954 		tep_func_repeat_format = "%d";
1955 	} else if (tracecmd_get_flags(handle) & TRACECMD_FL_IN_USECS) {
1956 		if (tep_test_flag(tracecmd_get_tep(handle), TEP_NSEC_OUTPUT))
1957 			tep_func_repeat_format = "%9.1d";
1958 		else
1959 			tep_func_repeat_format = "%6.1000d";
1960 	} else {
1961 		tep_func_repeat_format = "%12d";
1962 	}
1963 
1964 
1965 	if (show_stat)
1966 		otype = OUTPUT_STAT_ONLY;
1967 	/* yeah yeah, uname overrides stat */
1968 	if (show_uname)
1969 		otype = OUTPUT_UNAME_ONLY;
1970 	/* and version overrides uname! */
1971 	if (show_version)
1972 		otype = OUTPUT_VERSION_ONLY;
1973 	read_data_info(&handle_list, otype, global, align_ts);
1974 
1975 	list_for_each_entry(handles, &handle_list, list) {
1976 		tracecmd_close(handles->handle);
1977 	}
1978 	free_handles();
1979 	free_inputs();
1980 
1981 	finish_wakeup();
1982 
1983 	return;
1984 }
1985