aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2011-02-22 21:45:54 -0500
committerSteven Rostedt <rostedt@goodmis.org>2011-02-22 21:45:54 -0500
commitf7dedb40bd2969f990a78c82662a555c011da6fa (patch)
tree8ff8b81a36861c86cd8cf581233e7b93a1dffc3f
parente9fa08f59877a98b65cc2c26129c81778de31279 (diff)
trace-cmd: Allow multiple data files to be read
Let the user add -i multiple times to read multiple trace.dat files that will be merged sorted according to the timestamp that is given. Suggested-by: Thomas Taranowski <tom@baringforge.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--trace-local.h2
-rw-r--r--trace-read.c353
2 files changed, 259 insertions, 96 deletions
diff --git a/trace-local.h b/trace-local.h
index 73c38d2..72f6450 100644
--- a/trace-local.h
+++ b/trace-local.h
@@ -33,7 +33,7 @@ void usage(char **argv);
33extern int silence_warnings; 33extern int silence_warnings;
34extern int show_status; 34extern int show_status;
35 35
36struct tracecmd_input *read_trace_header(void); 36struct tracecmd_input *read_trace_header(const char *file);
37int read_trace_files(void); 37int read_trace_files(void);
38 38
39void trace_report(int argc, char **argv); 39void trace_report(int argc, char **argv);
diff --git a/trace-read.c b/trace-read.c
index 326054e..0e9ced8 100644
--- a/trace-read.c
+++ b/trace-read.c
@@ -39,6 +39,7 @@
39 39
40#include "trace-local.h" 40#include "trace-local.h"
41#include "trace-hash-local.h" 41#include "trace-hash-local.h"
42#include "list.h"
42 43
43static struct filter { 44static struct filter {
44 struct filter *next; 45 struct filter *next;
@@ -47,13 +48,30 @@ static struct filter {
47} *filter_strings; 48} *filter_strings;
48static struct filter **filter_next = &filter_strings; 49static struct filter **filter_next = &filter_strings;
49 50
50static struct event_filter *event_filters; 51struct handle_list {
51static struct event_filter *event_filter_out; 52 struct list_head list;
53 struct tracecmd_input *handle;
54 const char *file;
55 int cpus;
56 int done;
57 struct record *record;
58 struct event_filter *event_filters;
59 struct event_filter *event_filter_out;
60};
61static struct list_head handle_list;
62
63struct input_files {
64 struct list_head list;
65 const char *file;
66};
67static struct list_head input_files;
52 68
53static unsigned int page_size; 69static unsigned int page_size;
54static int input_fd; 70static int input_fd;
55const char *default_input_file = "trace.dat"; 71static const char *default_input_file = "trace.dat";
56const char *input_file; 72static const char *input_file;
73static int multi_inputs;
74static int max_file_size;
57 75
58static int filter_cpu = -1; 76static int filter_cpu = -1;
59static int *filter_cpus; 77static int *filter_cpus;
@@ -231,6 +249,55 @@ static void test_save(struct record *record, int cpu)
231} 249}
232#endif 250#endif
233 251
252static void add_input(const char *file)
253{
254 struct input_files *item;
255
256 item = malloc_or_die(sizeof(*item));
257 item->file = file;
258 list_add_tail(&item->list, &input_files);
259}
260
261static void add_handle(struct tracecmd_input *handle, const char *file)
262{
263 struct handle_list *item;
264
265 item = malloc_or_die(sizeof(*item));
266 memset(item, 0, sizeof(*item));
267 item->handle = handle;
268 item->file = file + strlen(file);
269 /* we want just the base name */
270 while (*item->file != '/' && item->file >= file)
271 item->file--;
272 item->file++;
273 if (strlen(item->file) > max_file_size)
274 max_file_size = strlen(item->file);
275
276 list_add_tail(&item->list, &handle_list);
277}
278
279static void free_inputs(void)
280{
281 struct input_files *item;
282
283 while (!list_empty(&input_files)) {
284 item = container_of(input_files.next, struct input_files, list);
285 list_del(&item->list);
286 free(item);
287 }
288}
289
290static void free_handles(void)
291{
292 struct handle_list *item;
293
294 while (!list_empty(&handle_list)) {
295 item = container_of(handle_list.next, struct handle_list, list);
296 list_del(&item->list);
297 free(item);
298 }
299}
300
234static void add_filter(const char *filter, int neg) 301static void add_filter(const char *filter, int neg)
235{ 302{
236 struct filter *ftr; 303 struct filter *ftr;
@@ -245,7 +312,7 @@ static void add_filter(const char *filter, int neg)
245 filter_next = &ftr->next; 312 filter_next = &ftr->next;
246} 313}
247 314
248static void process_filters(struct tracecmd_input *handle) 315static void process_filters(struct handle_list *handles)
249{ 316{
250 struct event_filter *event_filter; 317 struct event_filter *event_filter;
251 struct pevent *pevent; 318 struct pevent *pevent;
@@ -253,17 +320,17 @@ static void process_filters(struct tracecmd_input *handle)
253 char *errstr; 320 char *errstr;
254 int ret; 321 int ret;
255 322
256 pevent = tracecmd_get_pevent(handle); 323 pevent = tracecmd_get_pevent(handles->handle);
257 event_filters = pevent_filter_alloc(pevent); 324 handles->event_filters = pevent_filter_alloc(pevent);
258 event_filter_out = pevent_filter_alloc(pevent); 325 handles->event_filter_out = pevent_filter_alloc(pevent);
259 326
260 while (filter_strings) { 327 while (filter_strings) {
261 filter = filter_strings; 328 filter = filter_strings;
262 filter_strings = filter->next; 329 filter_strings = filter->next;
263 if (filter->neg) 330 if (filter->neg)
264 event_filter = event_filter_out; 331 event_filter = handles->event_filter_out;
265 else 332 else
266 event_filter = event_filters; 333 event_filter = handles->event_filters;
267 334
268 ret = pevent_filter_add_filter_str(event_filter, 335 ret = pevent_filter_add_filter_str(event_filter,
269 filter->filter, 336 filter->filter,
@@ -515,30 +582,21 @@ static void read_rest(void)
515 } while (r > 0); 582 } while (r > 0);
516} 583}
517 584
518static void read_data_info(struct tracecmd_input *handle) 585static struct record *
586get_next_record(struct handle_list *handles, int *next_cpu)
519{ 587{
520 unsigned long long ts; 588 unsigned long long ts;
521 struct record *record; 589 struct record *record;
522 int cpus; 590 int found = 0;
523 int next; 591 int next;
524 int cpu; 592 int cpu;
525 int ret; 593 int ret;
526 594
527 ret = tracecmd_init_data(handle); 595 if (handles->record)
528 if (ret < 0) 596 return handles->record;
529 die("failed to init data");
530
531 cpus = tracecmd_cpus(handle);
532 printf("cpus=%d\n", cpus);
533
534 /* Latency trace is just all ASCII */
535 if (ret > 0) {
536 read_rest();
537 return;
538 }
539 597
540 init_wakeup(handle); 598 if (handles->done)
541 process_filters(handle); 599 return NULL;
542 600
543 do { 601 do {
544 next = -1; 602 next = -1;
@@ -550,7 +608,7 @@ static void read_data_info(struct tracecmd_input *handle)
550 int i; 608 int i;
551 609
552 for (i = 0; (cpu = filter_cpus[i]) >= 0; i++) { 610 for (i = 0; (cpu = filter_cpus[i]) >= 0; i++) {
553 precord = tracecmd_peek_data(handle, cpu); 611 precord = tracecmd_peek_data(handles->handle, cpu);
554 if (precord && 612 if (precord &&
555 (!last_stamp || precord->ts < last_stamp)) { 613 (!last_stamp || precord->ts < last_stamp)) {
556 next_cpu = cpu; 614 next_cpu = cpu;
@@ -558,41 +616,123 @@ static void read_data_info(struct tracecmd_input *handle)
558 } 616 }
559 } 617 }
560 if (last_stamp) 618 if (last_stamp)
561 record = tracecmd_read_data(handle, next_cpu); 619 record = tracecmd_read_data(handles->handle, next_cpu);
562 else 620 else
563 record = NULL; 621 record = NULL;
564 622
565 } else if (filter_cpu >= 0) { 623 } else if (filter_cpu >= 0) {
566 cpu = filter_cpu; 624 cpu = filter_cpu;
567 record = tracecmd_read_data(handle, cpu); 625 record = tracecmd_read_data(handles->handle, cpu);
568 } else 626 } else
569 record = tracecmd_read_next_data(handle, &cpu); 627 record = tracecmd_read_next_data(handles->handle, &cpu);
570 628
571 if (record) { 629 if (record) {
572 ret = pevent_filter_match(event_filters, record); 630 ret = pevent_filter_match(handles->event_filters, record);
573 switch (ret) { 631 switch (ret) {
574 case FILTER_NONE: 632 case FILTER_NONE:
575 case FILTER_MATCH: 633 case FILTER_MATCH:
576 ret = pevent_filter_match(event_filter_out, record); 634 ret = pevent_filter_match(handles->event_filter_out, record);
577 if (ret != FILTER_MATCH) 635 if (ret != FILTER_MATCH) {
578 show_data(handle, record, next); 636 found = 1;
579 break; 637 break;
638 }
639 free_record(record);
580 } 640 }
581 free_record(record);
582 } 641 }
583 } while (record); 642 } while (record && !found);
584 643
585 pevent_filter_free(event_filters); 644 handles->record = record;
586 pevent_filter_free(event_filter_out); 645 if (!record)
646 handles->done = 1;
647 *next_cpu = next;
587 648
588 show_test(handle); 649 return record;
589} 650}
590 651
591struct tracecmd_input *read_trace_header(void) 652static void free_handle_record(struct handle_list *handles)
592{ 653{
593 input_fd = open(input_file, O_RDONLY); 654 if (!handles->record)
655 return;
656
657 free_record(handles->record);
658 handles->record = NULL;
659}
660
661static void print_handle_file(struct handle_list *handles)
662{
663 /* Only print file names if more than one file is read */
664 if (!multi_inputs)
665 return;
666 printf("%*s: ", max_file_size, handles->file);
667}
668
669static void read_data_info(struct list_head *handle_list)
670{
671 struct handle_list *handles;
672 struct handle_list *last_handle;
673 struct record *record;
674 struct record *last_record;
675 int last_cpu;
676 int cpus;
677 int next;
678 int ret;
679
680 list_for_each_entry(handles, handle_list, list) {
681
682 ret = tracecmd_init_data(handles->handle);
683 if (ret < 0)
684 die("failed to init data");
685
686 cpus = tracecmd_cpus(handles->handle);
687 handles->cpus = cpus;
688 print_handle_file(handles);
689 printf("cpus=%d\n", cpus);
690
691 /* Latency trace is just all ASCII */
692 if (ret > 0) {
693 if (multi_inputs)
694 die("latency traces do not work with multiple inputs");
695 read_rest();
696 return;
697 }
698
699 init_wakeup(handles->handle);
700 process_filters(handles);
701 }
702
703 do {
704 last_handle = NULL;
705 last_record = NULL;
706
707 list_for_each_entry(handles, handle_list, list) {
708 record = get_next_record(handles, &next);
709 if (!last_record ||
710 (record && record->ts < last_record->ts)) {
711 last_record = record;
712 last_handle = handles;
713 last_cpu = next;
714 }
715 }
716 if (last_record) {
717 print_handle_file(last_handle);
718 show_data(last_handle->handle, last_record, last_cpu);
719 free_handle_record(last_handle);
720 }
721 } while (last_record);
722
723 list_for_each_entry(handles, handle_list, list) {
724 pevent_filter_free(handles->event_filters);
725 pevent_filter_free(handles->event_filter_out);
726
727 show_test(handles->handle);
728 }
729}
730
731struct tracecmd_input *read_trace_header(const char *file)
732{
733 input_fd = open(file, O_RDONLY);
594 if (input_fd < 0) 734 if (input_fd < 0)
595 die("opening '%s'\n", input_file); 735 die("opening '%s'\n", file);
596 736
597 return tracecmd_alloc_fd(input_fd); 737 return tracecmd_alloc_fd(input_fd);
598} 738}
@@ -720,6 +860,8 @@ void trace_report (int argc, char **argv)
720 struct tracecmd_input *handle; 860 struct tracecmd_input *handle;
721 struct pevent *pevent; 861 struct pevent *pevent;
722 const char *functions = NULL; 862 const char *functions = NULL;
863 struct input_files *inputs;
864 struct handle_list *handles;
723 int show_funcs = 0; 865 int show_funcs = 0;
724 int show_endian = 0; 866 int show_endian = 0;
725 int show_page_size = 0; 867 int show_page_size = 0;
@@ -732,6 +874,9 @@ void trace_report (int argc, char **argv)
732 int neg = 0; 874 int neg = 0;
733 int c; 875 int c;
734 876
877 list_head_init(&handle_list);
878 list_head_init(&input_files);
879
735 if (argc < 2) 880 if (argc < 2)
736 usage(argv); 881 usage(argv);
737 882
@@ -760,7 +905,13 @@ void trace_report (int argc, char **argv)
760 usage(argv); 905 usage(argv);
761 break; 906 break;
762 case 'i': 907 case 'i':
763 input_file = optarg; 908 if (input_file) {
909 if (!multi_inputs)
910 add_input(input_file);
911 multi_inputs++;
912 add_input(optarg);
913 } else
914 input_file = optarg;
764 break; 915 break;
765 case 'F': 916 case 'F':
766 add_filter(optarg, neg); 917 add_filter(optarg, neg);
@@ -844,75 +995,87 @@ void trace_report (int argc, char **argv)
844 if (!input_file) 995 if (!input_file)
845 input_file = default_input_file; 996 input_file = default_input_file;
846 997
847 handle = read_trace_header(); 998 if (!multi_inputs)
848 if (!handle) 999 add_input(input_file);
849 die("error reading header"); 1000 else if (show_wakeup)
1001 die("Wakeup tracing can only be done on a single input file");
850 1002
851 page_size = tracecmd_page_size(handle); 1003 list_for_each_entry(inputs, &input_files, list) {
1004 handle = read_trace_header(inputs->file);
1005 if (!handle)
1006 die("error reading header for %s", inputs->file);
1007 add_handle(handle, inputs->file);
852 1008
853 if (show_page_size) { 1009 page_size = tracecmd_page_size(handle);
854 printf("file page size is %d, and host page size is %d\n",
855 page_size,
856 getpagesize());
857 return;
858 }
859 1010
860 pevent = tracecmd_get_pevent(handle); 1011 if (show_page_size) {
1012 printf("file page size is %d, and host page size is %d\n",
1013 page_size,
1014 getpagesize());
1015 return;
1016 }
861 1017
862 if (raw) 1018 pevent = tracecmd_get_pevent(handle);
863 pevent->print_raw = 1;
864 1019
865 if (test_filters) 1020 if (raw)
866 pevent->test_filters = 1; 1021 pevent->print_raw = 1;
867 1022
868 if (functions) 1023 if (test_filters)
869 add_functions(pevent, functions); 1024 pevent->test_filters = 1;
870 1025
871 if (show_endian) { 1026 if (functions)
872 printf("file is %s endian and host is %s endian\n", 1027 add_functions(pevent, functions);
873 pevent_is_file_bigendian(pevent) ? "big" : "little",
874 pevent_is_host_bigendian(pevent) ? "big" : "little");
875 return;
876 }
877 1028
878 if (print_events) { 1029 if (show_endian) {
879 tracecmd_print_events(handle); 1030 printf("file is %s endian and host is %s endian\n",
880 return; 1031 pevent_is_file_bigendian(pevent) ? "big" : "little",
881 } 1032 pevent_is_host_bigendian(pevent) ? "big" : "little");
1033 return;
1034 }
882 1035
883 if (tracecmd_read_headers(handle) < 0) 1036 if (print_events) {
884 return; 1037 tracecmd_print_events(handle);
1038 return;
1039 }
885 1040
886 if (show_funcs) { 1041 if (tracecmd_read_headers(handle) < 0)
887 pevent_print_funcs(pevent); 1042 return;
888 return;
889 }
890 if (show_printk) {
891 pevent_print_printk(pevent);
892 return;
893 }
894 1043
895 if (show_events) { 1044 if (show_funcs) {
896 struct event_format **events; 1045 pevent_print_funcs(pevent);
897 struct event_format *event; 1046 return;
898 int i; 1047 }
899 1048 if (show_printk) {
900 events = pevent_list_events(pevent, EVENT_SORT_SYSTEM); 1049 pevent_print_printk(pevent);
901 for (i = 0; events[i]; i++) { 1050 return;
902 event = events[i]; 1051 }
903 if (event->system) 1052
904 printf("%s:", event->system); 1053 if (show_events) {
905 printf("%s\n", event->name); 1054 struct event_format **events;
1055 struct event_format *event;
1056 int i;
1057
1058 events = pevent_list_events(pevent, EVENT_SORT_SYSTEM);
1059 for (i = 0; events[i]; i++) {
1060 event = events[i];
1061 if (event->system)
1062 printf("%s:", event->system);
1063 printf("%s\n", event->name);
1064 }
1065 return;
906 } 1066 }
907 return;
908 } 1067 }
909 1068
910 if (latency_format) 1069 if (latency_format)
911 pevent_set_latency_format(pevent, latency_format); 1070 pevent_set_latency_format(pevent, latency_format);
912 1071
913 read_data_info(handle); 1072 read_data_info(&handle_list);
914 1073
915 tracecmd_close(handle); 1074 list_for_each_entry(handles, &handle_list, list) {
1075 tracecmd_close(handles->handle);
1076 }
1077 free_handles();
1078 free_inputs();
916 1079
917 finish_wakeup(); 1080 finish_wakeup();
918 1081