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(®ex, 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(®ex, event->name, 0, NULL, 0) ||
1504 !regexec(®ex, 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