aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2009-12-18 13:32:10 -0500
committerSteven Rostedt <rostedt@goodmis.org>2009-12-18 13:38:29 -0500
commit8e5898fc7498693cab0b153eea5e37b302e307d2 (patch)
tree54bc25ec88b48a6214126b13d993bd901d7e732f
parent40a8521b53435a97e855c7d65486da41b30f9131 (diff)
parentb05f27dc7d0dab346e20795ce4d9f6d56d3e18ea (diff)
Merge branch 'trace-cmd' into trace-view
Fixed up the trace-graph and trace-cmd view to handle the new API Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--parse-events.c25
-rw-r--r--parse-events.h12
-rw-r--r--plugin_hrtimer.c13
-rw-r--r--plugin_mac80211.c14
-rw-r--r--plugin_sched_switch.c12
-rw-r--r--trace-cmd.c138
-rw-r--r--trace-cmd.h2
-rw-r--r--trace-ftrace.c55
-rw-r--r--trace-graph.c8
-rw-r--r--trace-input.c151
-rw-r--r--trace-read.c2
-rw-r--r--trace-view-store.c5
12 files changed, 323 insertions, 114 deletions
diff --git a/parse-events.c b/parse-events.c
index 49cde00..24ecb85 100644
--- a/parse-events.c
+++ b/parse-events.c
@@ -3113,13 +3113,14 @@ static void pretty_print(struct trace_seq *s, void *data, int size, struct event
3113 * and lock depth) and places it into the trace_seq. 3113 * and lock depth) and places it into the trace_seq.
3114 */ 3114 */
3115void pevent_data_lat_fmt(struct pevent *pevent, 3115void pevent_data_lat_fmt(struct pevent *pevent,
3116 struct trace_seq *s, void *data, int size __unused) 3116 struct trace_seq *s, struct record *record)
3117{ 3117{
3118 unsigned int lat_flags; 3118 unsigned int lat_flags;
3119 unsigned int pc; 3119 unsigned int pc;
3120 int lock_depth; 3120 int lock_depth;
3121 int hardirq; 3121 int hardirq;
3122 int softirq; 3122 int softirq;
3123 void *data = record->data;
3123 3124
3124 lat_flags = parse_common_flags(pevent, data); 3125 lat_flags = parse_common_flags(pevent, data);
3125 pc = parse_common_pc(pevent, data); 3126 pc = parse_common_pc(pevent, data);
@@ -3215,30 +3216,32 @@ const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid)
3215 * writes the print format into the trace_seq. 3216 * writes the print format into the trace_seq.
3216 */ 3217 */
3217void pevent_event_info(struct trace_seq *s, struct event_format *event, 3218void pevent_event_info(struct trace_seq *s, struct event_format *event,
3218 int cpu, void *data, int size, unsigned long long nsecs) 3219 struct record *record)
3219{ 3220{
3220 if (event->handler) 3221 if (event->handler)
3221 event->handler(s, data, size, event, cpu, nsecs); 3222 event->handler(s, record, event);
3222 else 3223 else
3223 pretty_print(s, data, size, event); 3224 pretty_print(s, record->data, record->size, event);
3224 3225
3225 trace_seq_terminate(s); 3226 trace_seq_terminate(s);
3226} 3227}
3227 3228
3228void pevent_print_event(struct pevent *pevent, struct trace_seq *s, 3229void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
3229 int cpu, void *data, int size, unsigned long long nsecs) 3230 struct record *record)
3230{ 3231{
3231 static char *spaces = " "; /* 20 spaces */ 3232 static char *spaces = " "; /* 20 spaces */
3232 struct event_format *event; 3233 struct event_format *event;
3233 unsigned long secs; 3234 unsigned long secs;
3234 unsigned long usecs; 3235 unsigned long usecs;
3235 const char *comm; 3236 const char *comm;
3237 void *data = record->data;
3238 int size = record->size;
3236 int type; 3239 int type;
3237 int pid; 3240 int pid;
3238 int len; 3241 int len;
3239 3242
3240 secs = nsecs / NSECS_PER_SEC; 3243 secs = record->ts / NSECS_PER_SEC;
3241 usecs = nsecs - secs * NSECS_PER_SEC; 3244 usecs = record->ts - secs * NSECS_PER_SEC;
3242 usecs = usecs / NSECS_PER_USEC; 3245 usecs = usecs / NSECS_PER_USEC;
3243 3246
3244 type = trace_parse_common_type(pevent, data); 3247 type = trace_parse_common_type(pevent, data);
@@ -3254,10 +3257,10 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
3254 3257
3255 if (pevent->latency_format) { 3258 if (pevent->latency_format) {
3256 trace_seq_printf(s, "%8.8s-%-5d %3d", 3259 trace_seq_printf(s, "%8.8s-%-5d %3d",
3257 comm, pid, cpu); 3260 comm, pid, record->cpu);
3258 pevent_data_lat_fmt(pevent, s, data, size); 3261 pevent_data_lat_fmt(pevent, s, record);
3259 } else 3262 } else
3260 trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, cpu); 3263 trace_seq_printf(s, "%16s-%-5d [%03d]", comm, pid, record->cpu);
3261 3264
3262 trace_seq_printf(s, " %5lu.%06lu: %s: ", secs, usecs, event->name); 3265 trace_seq_printf(s, " %5lu.%06lu: %s: ", secs, usecs, event->name);
3263 3266
@@ -3267,7 +3270,7 @@ void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
3267 trace_seq_printf(s, "%.*s", 20 - len, spaces); 3270 trace_seq_printf(s, "%.*s", 20 - len, spaces);
3268 3271
3269 if (event->handler) 3272 if (event->handler)
3270 event->handler(s, data, size, event, cpu, nsecs); 3273 event->handler(s, record, event);
3271 else 3274 else
3272 pretty_print(s, data, size, event); 3275 pretty_print(s, data, size, event);
3273 3276
diff --git a/parse-events.h b/parse-events.h
index 9b64b9d..00bdc44 100644
--- a/parse-events.h
+++ b/parse-events.h
@@ -20,6 +20,7 @@ struct record {
20 int record_size; /* size of binary record */ 20 int record_size; /* size of binary record */
21 int size; /* size of data */ 21 int size; /* size of data */
22 void *data; 22 void *data;
23 int cpu;
23}; 24};
24 25
25/* 26/*
@@ -61,9 +62,8 @@ struct pevent;
61struct event_format; 62struct event_format;
62 63
63typedef int (*pevent_event_handler_func)(struct trace_seq *s, 64typedef int (*pevent_event_handler_func)(struct trace_seq *s,
64 void *data, int size, 65 struct record *record,
65 struct event_format *event, int cpu, 66 struct event_format *event);
66 unsigned long long nsecs);
67 67
68typedef int (*pevent_plugin_load_func)(struct pevent *pevent); 68typedef int (*pevent_plugin_load_func)(struct pevent *pevent);
69 69
@@ -350,7 +350,7 @@ int pevent_register_print_string(struct pevent *pevent, char *fmt,
350int pevent_pid_is_registered(struct pevent *pevent, int pid); 350int pevent_pid_is_registered(struct pevent *pevent, int pid);
351 351
352void pevent_print_event(struct pevent *pevent, struct trace_seq *s, 352void pevent_print_event(struct pevent *pevent, struct trace_seq *s,
353 int cpu, void *data, int size, unsigned long long nsecs); 353 struct record *record);
354 354
355int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size); 355int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size);
356 356
@@ -374,13 +374,13 @@ struct event_format *
374pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name); 374pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name);
375 375
376void pevent_data_lat_fmt(struct pevent *pevent, 376void pevent_data_lat_fmt(struct pevent *pevent,
377 struct trace_seq *s, void *data, int size __unused); 377 struct trace_seq *s, struct record *record);
378int pevent_data_type(struct pevent *pevent, struct record *rec); 378int pevent_data_type(struct pevent *pevent, struct record *rec);
379struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type); 379struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type);
380int pevent_data_pid(struct pevent *pevent, struct record *rec); 380int pevent_data_pid(struct pevent *pevent, struct record *rec);
381const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid); 381const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid);
382void pevent_event_info(struct trace_seq *s, struct event_format *event, 382void pevent_event_info(struct trace_seq *s, struct event_format *event,
383 int cpu, void *data, int size, unsigned long long nsecs); 383 struct record *record);
384 384
385struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type); 385struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type);
386 386
diff --git a/plugin_hrtimer.c b/plugin_hrtimer.c
index 01f8ff3..afc5afe 100644
--- a/plugin_hrtimer.c
+++ b/plugin_hrtimer.c
@@ -30,10 +30,11 @@ static void print_field(struct trace_seq *s, const char *fmt,
30 trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name); 30 trace_seq_printf(s, "CAN'T FIND FIELD \"%s\"", name);
31} 31}
32 32
33static int timer_expire_handler(struct trace_seq *s, void *data, int size, 33static int timer_expire_handler(struct trace_seq *s, struct record *record,
34 struct event_format *event, int cpu, 34 struct event_format *event)
35 unsigned long long nsecs)
36{ 35{
36 void *data = record->data;
37
37 trace_seq_printf(s, "hrtimer="); 38 trace_seq_printf(s, "hrtimer=");
38 39
39 if (_print_field(s, "0x%llx", event, "timer", data) == -1) 40 if (_print_field(s, "0x%llx", event, "timer", data) == -1)
@@ -46,12 +47,12 @@ static int timer_expire_handler(struct trace_seq *s, void *data, int size,
46 return 0; 47 return 0;
47} 48}
48 49
49static int timer_start_handler(struct trace_seq *s, void *data, int size, 50static int timer_start_handler(struct trace_seq *s, struct record *record,
50 struct event_format *event, int cpu, 51 struct event_format *event)
51 unsigned long long nsecs)
52{ 52{
53 struct pevent *pevent = event->pevent; 53 struct pevent *pevent = event->pevent;
54 struct format_field *fn = pevent_find_field(event, "function"); 54 struct format_field *fn = pevent_find_field(event, "function");
55 void *data = record->data;
55 56
56 trace_seq_printf(s, "hrtimer="); 57 trace_seq_printf(s, "hrtimer=");
57 58
diff --git a/plugin_mac80211.c b/plugin_mac80211.c
index 766d9ce..497d564 100644
--- a/plugin_mac80211.c
+++ b/plugin_mac80211.c
@@ -145,10 +145,11 @@ static void _print_flag(struct trace_seq *s, struct event_format *event,
145#define SFX(fn) _print_field(s, fn ":%#x", event, fn, data) 145#define SFX(fn) _print_field(s, fn ":%#x", event, fn, data)
146#define SP() trace_seq_putc(s, ' ') 146#define SP() trace_seq_putc(s, ' ')
147 147
148static int drv_bss_info_changed(struct trace_seq *s, void *data, int size, 148static int drv_bss_info_changed(struct trace_seq *s, struct record *record,
149 struct event_format *event, int cpu, 149 struct event_format *event)
150 unsigned long long nsecs)
151{ 150{
151 void *data = record->data;
152
152 print_string(s, event, "wiphy_name", data); 153 print_string(s, event, "wiphy_name", data);
153 trace_seq_printf(s, " vif:"); 154 trace_seq_printf(s, " vif:");
154 print_string(s, event, "vif_name", data); 155 print_string(s, event, "vif_name", data);
@@ -172,10 +173,11 @@ static int drv_bss_info_changed(struct trace_seq *s, void *data, int size,
172 return 0; 173 return 0;
173} 174}
174 175
175static int drv_config(struct trace_seq *s, void *data, 176static int drv_config(struct trace_seq *s, struct record *record,
176 int size, struct event_format *event, int cpu, 177 struct event_format *event)
177 unsigned long long nsecs)
178{ 178{
179 void *data = record->data;
180
179 print_string(s, event, "wiphy_name", data); 181 print_string(s, event, "wiphy_name", data);
180 trace_seq_putc(s, ' '); 182 trace_seq_putc(s, ' ');
181 print_flag(s, event, "flags", data, 183 print_flag(s, event, "flags", data,
diff --git a/plugin_sched_switch.c b/plugin_sched_switch.c
index 4690f2f..0f3b857 100644
--- a/plugin_sched_switch.c
+++ b/plugin_sched_switch.c
@@ -47,12 +47,12 @@ static void write_state(struct trace_seq *s, int val)
47 trace_seq_putc(s, 'R'); 47 trace_seq_putc(s, 'R');
48} 48}
49 49
50static int sched_wakeup_handler(struct trace_seq *s, void *data, int size, 50static int sched_wakeup_handler(struct trace_seq *s, struct record *record,
51 struct event_format *event, int cpu, 51 struct event_format *event)
52 unsigned long long nsecs)
53{ 52{
54 struct format_field *field; 53 struct format_field *field;
55 unsigned long long val; 54 unsigned long long val;
55 void *data = record->data;
56 56
57 if (get_field_val(s, data, event, "common_pid", &val, 1)) 57 if (get_field_val(s, data, event, "common_pid", &val, 1))
58 return trace_seq_putc(s, '!'); 58 return trace_seq_putc(s, '!');
@@ -102,12 +102,12 @@ static int sched_wakeup_handler(struct trace_seq *s, void *data, int size,
102 return 0; 102 return 0;
103} 103}
104 104
105static int sched_switch_handler(struct trace_seq *s, void *data, int size, 105static int sched_switch_handler(struct trace_seq *s, struct record *record,
106 struct event_format *event, int cpu, 106 struct event_format *event)
107 unsigned long long nsecs)
108{ 107{
109 struct format_field *field; 108 struct format_field *field;
110 unsigned long long val; 109 unsigned long long val;
110 void *data = record->data;
111 111
112 if (get_field_val(s, data, event, "prev_pid", &val, 1)) 112 if (get_field_val(s, data, event, "prev_pid", &val, 1))
113 return trace_seq_putc(s, '!'); 113 return trace_seq_putc(s, '!');
diff --git a/trace-cmd.c b/trace-cmd.c
index cfd8ba5..cd45a6e 100644
--- a/trace-cmd.c
+++ b/trace-cmd.c
@@ -145,6 +145,19 @@ static void stop_threads(void)
145 } 145 }
146} 146}
147 147
148static void flush_threads(void)
149{
150 int i;
151
152 if (!cpu_count)
153 return;
154
155 for (i = 0; i < cpu_count; i++) {
156 if (pids[i] > 0)
157 kill(pids[i], SIGUSR1);
158 }
159}
160
148void die(char *fmt, ...) 161void die(char *fmt, ...)
149{ 162{
150 va_list ap; 163 va_list ap;
@@ -569,6 +582,12 @@ static void finish(int sig)
569 finished = 1; 582 finished = 1;
570} 583}
571 584
585static void flush(int sig)
586{
587 if (recorder)
588 tracecmd_stop_recording(recorder);
589}
590
572static int create_recorder(int cpu) 591static int create_recorder(int cpu)
573{ 592{
574 char *file; 593 char *file;
@@ -582,6 +601,7 @@ static int create_recorder(int cpu)
582 return pid; 601 return pid;
583 602
584 signal(SIGINT, finish); 603 signal(SIGINT, finish);
604 signal(SIGUSR1, flush);
585 605
586 /* do not kill tasks on error */ 606 /* do not kill tasks on error */
587 cpu_count = 0; 607 cpu_count = 0;
@@ -593,7 +613,8 @@ static int create_recorder(int cpu)
593 613
594 if (!recorder) 614 if (!recorder)
595 die ("can't create recorder"); 615 die ("can't create recorder");
596 tracecmd_start_recording(recorder, sleep_time); 616 while (!finished)
617 tracecmd_start_recording(recorder, sleep_time);
597 tracecmd_free_recorder(recorder); 618 tracecmd_free_recorder(recorder);
598 619
599 exit(0); 620 exit(0);
@@ -644,6 +665,46 @@ static void record_data(void)
644 tracecmd_output_close(handle); 665 tracecmd_output_close(handle);
645} 666}
646 667
668static int trace_empty(void)
669{
670 char *path;
671 FILE *fp;
672 char *line = NULL;
673 size_t size;
674 ssize_t n;
675 int ret;
676
677 /*
678 * Test if the trace file is empty.
679 *
680 * Yes, this is a heck of a hack. What is done here
681 * is to read the trace file and ignore the
682 * lines starting with '#', and if we get a line
683 * that is without a '#' the trace is not empty.
684 * Otherwise it is.
685 */
686 path = get_tracing_file("trace");
687 fp = fopen(path, "r");
688 if (!fp)
689 die("reading '%s'", path);
690
691 do {
692 n = getline(&line, &size, fp);
693 if (!line)
694 ret = 1;
695 else if (line[0] != '#')
696 ret = 0;
697 if (n < 0)
698 ret = 1;
699 } while (line && n > 0);
700
701 put_tracing_file(path);
702
703 fclose(fp);
704
705 return ret;
706}
707
647void usage(char **argv) 708void usage(char **argv)
648{ 709{
649 char *arg = argv[0]; 710 char *arg = argv[0];
@@ -669,6 +730,9 @@ void usage(char **argv)
669 " Uses same options as record, but does not run a command.\n" 730 " Uses same options as record, but does not run a command.\n"
670 " It only enables the tracing and exits\n" 731 " It only enables the tracing and exits\n"
671 "\n" 732 "\n"
733 " %s extract [-p plugin][-O option][-o file]\n"
734 " Uses same options as record, but only reads an existing trace.\n"
735 "\n"
672 " %s stop\n" 736 " %s stop\n"
673 " Stops the tracer from recording more data.\n" 737 " Stops the tracer from recording more data.\n"
674 " Used in conjunction with start\n" 738 " Used in conjunction with start\n"
@@ -689,7 +753,7 @@ void usage(char **argv)
689 " -e list available events\n" 753 " -e list available events\n"
690 " -p list available plugins\n" 754 " -p list available plugins\n"
691 " -o list available options\n" 755 " -o list available options\n"
692 "\n", p, TRACECMD_VERSION, p, p, p, p, p, p); 756 "\n", p, TRACECMD_VERSION, p, p, p, p, p, p, p);
693 exit(-1); 757 exit(-1);
694} 758}
695 759
@@ -705,6 +769,7 @@ int main (int argc, char **argv)
705 int events = 0; 769 int events = 0;
706 int options = 0; 770 int options = 0;
707 int record = 0; 771 int record = 0;
772 int extract = 0;
708 int run_command = 0; 773 int run_command = 0;
709 int neg_event = 0; 774 int neg_event = 0;
710 int fset; 775 int fset;
@@ -724,7 +789,8 @@ int main (int argc, char **argv)
724 trace_view(argc, argv); 789 trace_view(argc, argv);
725 exit(0); 790 exit(0);
726 } else if ((record = (strcmp(argv[1], "record") == 0)) || 791 } else if ((record = (strcmp(argv[1], "record") == 0)) ||
727 (strcmp(argv[1], "start") == 0)) { 792 (strcmp(argv[1], "start") == 0) ||
793 ((extract = strcmp(argv[1], "extract") == 0))) {
728 794
729 while ((c = getopt(argc-1, argv+1, "+he:p:do:O:s:v")) >= 0) { 795 while ((c = getopt(argc-1, argv+1, "+he:p:do:O:s:v")) >= 0) {
730 switch (c) { 796 switch (c) {
@@ -732,6 +798,8 @@ int main (int argc, char **argv)
732 usage(argv); 798 usage(argv);
733 break; 799 break;
734 case 'e': 800 case 'e':
801 if (extract)
802 usage(argv);
735 events = 1; 803 events = 1;
736 event = malloc_or_die(sizeof(*event)); 804 event = malloc_or_die(sizeof(*event));
737 event->event = optarg; 805 event->event = optarg;
@@ -740,6 +808,8 @@ int main (int argc, char **argv)
740 event_selection = event; 808 event_selection = event;
741 break; 809 break;
742 case 'v': 810 case 'v':
811 if (extract)
812 usage(argv);
743 neg_event = 1; 813 neg_event = 1;
744 break; 814 break;
745 case 'p': 815 case 'p':
@@ -749,10 +819,12 @@ int main (int argc, char **argv)
749 fprintf(stderr, " plugin %s\n", plugin); 819 fprintf(stderr, " plugin %s\n", plugin);
750 break; 820 break;
751 case 'd': 821 case 'd':
822 if (extract)
823 usage(argv);
752 disable = 1; 824 disable = 1;
753 break; 825 break;
754 case 'o': 826 case 'o':
755 if (!record) 827 if (!record && !extract)
756 die("start does not take output\n" 828 die("start does not take output\n"
757 "Did you mean 'record'?"); 829 "Did you mean 'record'?");
758 if (output) 830 if (output)
@@ -764,6 +836,8 @@ int main (int argc, char **argv)
764 set_option(option); 836 set_option(option);
765 break; 837 break;
766 case 's': 838 case 's':
839 if (extract)
840 usage(argv);
767 sleep_time = atoi(optarg); 841 sleep_time = atoi(optarg);
768 break; 842 break;
769 } 843 }
@@ -827,20 +901,26 @@ int main (int argc, char **argv)
827 if (!record) 901 if (!record)
828 die("Command start does not take any commands\n" 902 die("Command start does not take any commands\n"
829 "Did you mean 'record'?"); 903 "Did you mean 'record'?");
904 if (extract)
905 die("Command extract does not take any commands\n"
906 "Did you mean 'record'?");
830 run_command = 1; 907 run_command = 1;
831 } 908 }
832 909
833 if (!events && !plugin) 910 if (!events && !plugin && !extract)
834 die("no event or plugin was specified... aborting"); 911 die("no event or plugin was specified... aborting");
835 912
836 if (output) 913 if (output)
837 output_file = output; 914 output_file = output;
838 915
839 fset = set_ftrace(!disable); 916 if (!extract) {
840 disable_all(); 917 fset = set_ftrace(!disable);
918 disable_all();
919
920 if (events)
921 enable_events();
922 }
841 923
842 if (events)
843 enable_events();
844 if (plugin) { 924 if (plugin) {
845 /* 925 /*
846 * Latency tracers just save the trace and kill 926 * Latency tracers just save the trace and kill
@@ -856,33 +936,41 @@ int main (int argc, char **argv)
856 if (fset < 0 && (strcmp(plugin, "function") == 0 || 936 if (fset < 0 && (strcmp(plugin, "function") == 0 ||
857 strcmp(plugin, "function_graph") == 0)) 937 strcmp(plugin, "function_graph") == 0))
858 die("function tracing not configured on this kernel"); 938 die("function tracing not configured on this kernel");
859 set_plugin(plugin); 939 if (!extract)
940 set_plugin(plugin);
860 } 941 }
861 942
862 if (record) { 943 if (record || extract) {
863 if (!latency) 944 if (!latency)
864 start_threads(); 945 start_threads();
865 signal(SIGINT, finish); 946 signal(SIGINT, finish);
866 } 947 }
867 948
868 enable_tracing(); 949 if (extract) {
869 if (latency) 950 while (!finished && !trace_empty()) {
870 reset_max_latency(); 951 flush_threads();
952 sleep(1);
953 }
954 } else {
955 enable_tracing();
956 if (latency)
957 reset_max_latency();
871 958
872 if (!record) 959 if (!record)
873 exit(0); 960 exit(0);
961
962 if (run_command)
963 run_cmd((argc - optind) - 1, &argv[optind + 1]);
964 else {
965 /* sleep till we are woken with Ctrl^C */
966 printf("Hit Ctrl^C to stop recording\n");
967 while (!finished)
968 sleep(10);
969 }
874 970
875 if (run_command) 971 disable_tracing();
876 run_cmd((argc - optind) - 1, &argv[optind + 1]);
877 else {
878 /* sleep till we are woken with Ctrl^C */
879 printf("Hit Ctrl^C to stop recording\n");
880 while (!finished)
881 sleep(10);
882 } 972 }
883 973
884 disable_tracing();
885
886 stop_threads(); 974 stop_threads();
887 975
888 record_data(); 976 record_data();
diff --git a/trace-cmd.h b/trace-cmd.h
index a5cc217..f6141f4 100644
--- a/trace-cmd.h
+++ b/trace-cmd.h
@@ -72,6 +72,8 @@ struct record *
72tracecmd_read_cpu_first(struct tracecmd_input *handle, int cpu); 72tracecmd_read_cpu_first(struct tracecmd_input *handle, int cpu);
73struct record * 73struct record *
74tracecmd_read_cpu_last(struct tracecmd_input *handle, int cpu); 74tracecmd_read_cpu_last(struct tracecmd_input *handle, int cpu);
75int tracecmd_refresh_record(struct tracecmd_input *handle,
76 struct record *record);
75 77
76int tracecmd_set_cpu_to_timestamp(struct tracecmd_input *handle, 78int tracecmd_set_cpu_to_timestamp(struct tracecmd_input *handle,
77 int cpu, unsigned long long ts); 79 int cpu, unsigned long long ts);
diff --git a/trace-ftrace.c b/trace-ftrace.c
index 9dfe04d..459f74b 100644
--- a/trace-ftrace.c
+++ b/trace-ftrace.c
@@ -28,13 +28,13 @@ static int get_field_val(struct trace_seq *s, void *data,
28 return 0; 28 return 0;
29} 29}
30 30
31static int function_handler(struct trace_seq *s, void *data, int size, 31static int function_handler(struct trace_seq *s, struct record *record,
32 struct event_format *event, int cpu, 32 struct event_format *event)
33 unsigned long long nsecs)
34{ 33{
35 struct pevent *pevent = event->pevent; 34 struct pevent *pevent = event->pevent;
36 unsigned long long function; 35 unsigned long long function;
37 const char *func; 36 const char *func;
37 void *data = record->data;
38 38
39 if (get_field_val(s, data, event, "ip", &function)) 39 if (get_field_val(s, data, event, "ip", &function))
40 return trace_seq_putc(s, '!'); 40 return trace_seq_putc(s, '!');
@@ -220,13 +220,15 @@ static int print_graph_nested(struct trace_seq *s,
220} 220}
221 221
222static int 222static int
223fgraph_ent_handler(struct trace_seq *s, void *data, int size, 223fgraph_ent_handler(struct trace_seq *s, struct record *record,
224 struct event_format *event, int cpu, 224 struct event_format *event)
225 unsigned long long nsecs)
226{ 225{
227 struct record *rec; 226 struct record *rec;
228 void *copy_data; 227 void *copy_data;
229 unsigned long long val, pid; 228 unsigned long long val, pid;
229 void *data = record->data;
230 int size = record->size;
231 int cpu = record->cpu;
230 int ret; 232 int ret;
231 233
232 if (get_field_val(s, data, event, "common_pid", &pid)) 234 if (get_field_val(s, data, event, "common_pid", &pid))
@@ -248,22 +250,47 @@ fgraph_ent_handler(struct trace_seq *s, void *data, int size,
248 rec = tracecmd_peek_data(tracecmd_curr_thread_handle, cpu); 250 rec = tracecmd_peek_data(tracecmd_curr_thread_handle, cpu);
249 if (rec) 251 if (rec)
250 rec = get_return_for_leaf(s, cpu, pid, val, rec); 252 rec = get_return_for_leaf(s, cpu, pid, val, rec);
251 if (rec) 253
254 if (rec) {
255 /*
256 * The record returned needs to be freed.
257 * We also do a new peek on this CPU to update the
258 * record cache. (peek caches the record, but the
259 * refresh below will update the CPU iterator.
260 * If peek has a record in cache, it will update the
261 * iterator to that)
262 */
252 ret = print_graph_entry_leaf(s, event, data, rec); 263 ret = print_graph_entry_leaf(s, event, data, rec);
253 else 264 free_record(rec);
265 tracecmd_peek_data(tracecmd_curr_thread_handle, cpu);
266 } else
254 ret = print_graph_nested(s, event, data); 267 ret = print_graph_nested(s, event, data);
255 268
256 free(data); 269 free(data);
270
271 /*
272 * The above peek may unmap the record given to us.
273 * But callers may still have a reference to that record.
274 * We need to make sure it is still mapped.
275 *
276 * Note, this causes a known bug. If the last item in the trace
277 * was a leaf function, we can't remove it. The peek cache
278 * above will be NULL (no records after the leaf) so a new peek
279 * will simply read the return entry of the leaf and print it
280 * again.
281 */
282 tracecmd_refresh_record(tracecmd_curr_thread_handle,
283 record);
257 return ret; 284 return ret;
258} 285}
259 286
260static int 287static int
261fgraph_ret_handler(struct trace_seq *s, void *data, int size, 288fgraph_ret_handler(struct trace_seq *s, struct record *record,
262 struct event_format *event, int cpu, 289 struct event_format *event)
263 unsigned long long nsecs)
264{ 290{
265 unsigned long long rettime, calltime; 291 unsigned long long rettime, calltime;
266 unsigned long long duration, depth; 292 unsigned long long duration, depth;
293 void *data = record->data;
267 int i; 294 int i;
268 295
269 if (get_field_val(s, data, event, "rettime", &rettime)) 296 if (get_field_val(s, data, event, "rettime", &rettime))
@@ -291,13 +318,13 @@ fgraph_ret_handler(struct trace_seq *s, void *data, int size,
291} 318}
292 319
293static int 320static int
294trace_stack_handler(struct trace_seq *s, void *data, int size, 321trace_stack_handler(struct trace_seq *s, struct record *record,
295 struct event_format *event, int cpu, 322 struct event_format *event)
296 unsigned long long nsecs)
297{ 323{
298 struct format_field *field; 324 struct format_field *field;
299 unsigned long long addr; 325 unsigned long long addr;
300 const char *func; 326 const char *func;
327 void *data = record->data;
301 int ret; 328 int ret;
302 int i; 329 int i;
303 330
diff --git a/trace-graph.c b/trace-graph.c
index 4303a0a..b36c636 100644
--- a/trace-graph.c
+++ b/trace-graph.c
@@ -142,8 +142,7 @@ static void print_rec_info(struct record *record, struct pevent *pevent, int cpu
142 } 142 }
143 trace_seq_puts(&s, event->name); 143 trace_seq_puts(&s, event->name);
144 trace_seq_putc(&s, ':'); 144 trace_seq_putc(&s, ':');
145 pevent_event_info(&s, event, cpu, record->data, record->size, 145 pevent_event_info(&s, event, record);
146 record->ts);
147 trace_seq_putc(&s, '\n'); 146 trace_seq_putc(&s, '\n');
148 trace_seq_do_printf(&s); 147 trace_seq_do_printf(&s);
149} 148}
@@ -285,10 +284,9 @@ static void draw_cpu_info(struct graph_info *ginfo, gint cpu, gint x, gint y)
285 if (event) { 284 if (event) {
286 trace_seq_puts(&s, event->name); 285 trace_seq_puts(&s, event->name);
287 trace_seq_putc(&s, '\n'); 286 trace_seq_putc(&s, '\n');
288 pevent_data_lat_fmt(pevent, &s, record->data, record->size); 287 pevent_data_lat_fmt(pevent, &s, record);
289 trace_seq_putc(&s, '\n'); 288 trace_seq_putc(&s, '\n');
290 pevent_event_info(&s, event, cpu, record->data, record->size, 289 pevent_event_info(&s, event, record);
291 record->ts);
292 trace_seq_putc(&s, '\n'); 290 trace_seq_putc(&s, '\n');
293 } else 291 } else
294 trace_seq_printf(&s, "UNKNOW EVENT %d\n", type); 292 trace_seq_printf(&s, "UNKNOW EVENT %d\n", type);
diff --git a/trace-input.c b/trace-input.c
index ee9177f..8cc8865 100644
--- a/trace-input.c
+++ b/trace-input.c
@@ -495,6 +495,11 @@ static unsigned int ts4host(struct tracecmd_input *handle,
495 return type_len_ts >> 5; 495 return type_len_ts >> 5;
496} 496}
497 497
498static unsigned int read_type_len_ts(struct tracecmd_input *handle, void *ptr)
499{
500 return data2host4(handle->pevent, ptr);
501}
502
498static int calc_index(struct tracecmd_input *handle, 503static int calc_index(struct tracecmd_input *handle,
499 void *ptr, int cpu) 504 void *ptr, int cpu)
500{ 505{
@@ -574,9 +579,21 @@ static int get_read_page(struct tracecmd_input *handle, int cpu,
574 return 0; 579 return 0;
575} 580}
576 581
582/*
583 * get_page maps a page for a given cpu.
584 *
585 * Returns 1 if the page was already mapped,
586 * 0 if it mapped successfully
587 * -1 on error
588 */
577static int get_page(struct tracecmd_input *handle, int cpu, 589static int get_page(struct tracecmd_input *handle, int cpu,
578 off64_t offset) 590 off64_t offset)
579{ 591{
592 /* Don't map if the page is already where we want */
593 if (handle->cpu_data[cpu].offset == offset &&
594 handle->cpu_data[cpu].page)
595 return 1;
596
580 if (offset & (handle->page_size - 1)) { 597 if (offset & (handle->page_size - 1)) {
581 errno = -EINVAL; 598 errno = -EINVAL;
582 die("bad page offset %llx", offset); 599 die("bad page offset %llx", offset);
@@ -656,7 +673,7 @@ read_old_format(struct tracecmd_input *handle, void **ptr, int cpu)
656 673
657 index = calc_index(handle, *ptr, cpu); 674 index = calc_index(handle, *ptr, cpu);
658 675
659 type_len_ts = data2host4(pevent, *ptr); 676 type_len_ts = read_type_len_ts(handle, *ptr);
660 *ptr += 4; 677 *ptr += 4;
661 678
662 type = type4host(handle, type_len_ts); 679 type = type4host(handle, type_len_ts);
@@ -769,7 +786,7 @@ find_and_read_event(struct tracecmd_input *handle, unsigned long long offset,
769 /* Move this cpu index to point to this offest */ 786 /* Move this cpu index to point to this offest */
770 page_offset = offset & ~(handle->page_size - 1); 787 page_offset = offset & ~(handle->page_size - 1);
771 788
772 if (get_page(handle, cpu, page_offset)) 789 if (get_page(handle, cpu, page_offset) < 0)
773 return NULL; 790 return NULL;
774 791
775 if (pcpu) 792 if (pcpu)
@@ -815,6 +832,58 @@ tracecmd_read_at(struct tracecmd_input *handle, unsigned long long offset,
815} 832}
816 833
817/** 834/**
835 * tracecmd_refresh_record - remaps the records data
836 * @handle: input handle for the trace.dat file
837 * @record: the record to be refreshed
838 *
839 * A record data points to a mmap section of memory.
840 * by reading new records the mmap section may be unmapped.
841 * This will refresh the record's data mapping.
842 *
843 * Returns 1 if page is still mapped (does not modify CPU iterator)
844 * 0 on successful mapping (was not mapped before,
845 * This will update CPU iterator to point to
846 * the next record)
847 * -1 on error.
848 */
849int tracecmd_refresh_record(struct tracecmd_input *handle,
850 struct record *record)
851{
852 unsigned long long page_offset;
853 int cpu = record->cpu;
854 struct cpu_data *cpu_data = &handle->cpu_data[cpu];
855 unsigned int type_len_ts;
856 unsigned int len;
857 int index;
858 int ret;
859
860 page_offset = record->offset & ~(handle->page_size - 1);
861 index = record->offset & (handle->page_size - 1);
862
863 ret = get_page(handle, record->cpu, page_offset) < 0;
864 if (ret < 0)
865 return -1;
866
867 /* If the page is still mapped, there's nothing to do */
868 if (ret)
869 return 1;
870
871 record->data = cpu_data->page + index;
872
873 type_len_ts = read_type_len_ts(handle, record->data);
874 len = len4host(handle, type_len_ts);
875
876 /* The data starts either 4 or 8 bytes from offset */
877 record->data += len ? 4 : 8;
878
879 /* The get_page resets the index, set the index after this record */
880 cpu_data->index = index + record->record_size;
881 cpu_data->timestamp = record->ts;
882
883 return 0;
884}
885
886/**
818 * tracecmd_read_cpu_first - get the first record in a CPU 887 * tracecmd_read_cpu_first - get the first record in a CPU
819 * @handle: input handle for the trace.dat file 888 * @handle: input handle for the trace.dat file
820 * @cpu: the CPU to search 889 * @cpu: the CPU to search
@@ -918,7 +987,7 @@ tracecmd_set_cpu_to_timestamp(struct tracecmd_input *handle, int cpu,
918 } 987 }
919 988
920 while (start < end) { 989 while (start < end) {
921 if (get_page(handle, cpu, next)) 990 if (get_page(handle, cpu, next) < 0)
922 return -1; 991 return -1;
923 992
924 if (cpu_data->timestamp == ts) 993 if (cpu_data->timestamp == ts)
@@ -962,7 +1031,7 @@ translate_data(struct tracecmd_input *handle,
962 unsigned int type_len_ts; 1031 unsigned int type_len_ts;
963 unsigned int type_len; 1032 unsigned int type_len;
964 1033
965 type_len_ts = data2host4(pevent, *ptr); 1034 type_len_ts = read_type_len_ts(handle, *ptr);
966 *ptr += 4; 1035 *ptr += 4;
967 1036
968 type_len = type_len4host(handle, type_len_ts); 1037 type_len = type_len4host(handle, type_len_ts);
@@ -1020,31 +1089,31 @@ struct record *
1020tracecmd_translate_data(struct tracecmd_input *handle, 1089tracecmd_translate_data(struct tracecmd_input *handle,
1021 void *ptr, int size) 1090 void *ptr, int size)
1022{ 1091{
1023 struct record *data; 1092 struct record *record;
1024 unsigned int type_len; 1093 unsigned int type_len;
1025 1094
1026 /* minimum record read is 8, (warn?) (TODO: make 8 into macro) */ 1095 /* minimum record read is 8, (warn?) (TODO: make 8 into macro) */
1027 if (size < 8) 1096 if (size < 8)
1028 return NULL; 1097 return NULL;
1029 1098
1030 data = malloc(sizeof(*data)); 1099 record = malloc(sizeof(*record));
1031 if (!data) 1100 if (!record)
1032 return NULL; 1101 return NULL;
1033 memset(data, 0, sizeof(*data)); 1102 memset(record, 0, sizeof(*record));
1034 1103
1035 data->data = ptr; 1104 record->data = ptr;
1036 type_len = translate_data(handle, &data->data, &data->ts, &data->size); 1105 type_len = translate_data(handle, &record->data, &record->ts, &record->size);
1037 switch (type_len) { 1106 switch (type_len) {
1038 case RINGBUF_TYPE_PADDING: 1107 case RINGBUF_TYPE_PADDING:
1039 case RINGBUF_TYPE_TIME_EXTEND: 1108 case RINGBUF_TYPE_TIME_EXTEND:
1040 case RINGBUF_TYPE_TIME_STAMP: 1109 case RINGBUF_TYPE_TIME_STAMP:
1041 data->data = NULL; 1110 record->data = NULL;
1042 break; 1111 break;
1043 default: 1112 default:
1044 break; 1113 break;
1045 } 1114 }
1046 1115
1047 return data; 1116 return record;
1048} 1117}
1049 1118
1050/** 1119/**
@@ -1061,19 +1130,38 @@ struct record *
1061tracecmd_peek_data(struct tracecmd_input *handle, int cpu) 1130tracecmd_peek_data(struct tracecmd_input *handle, int cpu)
1062{ 1131{
1063 struct pevent *pevent = handle->pevent; 1132 struct pevent *pevent = handle->pevent;
1064 struct record *data; 1133 struct record *record;
1065 void *page = handle->cpu_data[cpu].page; 1134 void *page = handle->cpu_data[cpu].page;
1066 int index = handle->cpu_data[cpu].index; 1135 int index = handle->cpu_data[cpu].index;
1067 void *ptr = page + index; 1136 void *ptr = page + index;
1068 unsigned long long extend; 1137 unsigned long long extend;
1069 unsigned int type_len; 1138 unsigned int type_len;
1070 int length; 1139 int length;
1140 int ret;
1071 1141
1072 /* Hack to work around function graph read ahead */ 1142 /* Hack to work around function graph read ahead */
1073 tracecmd_curr_thread_handle = handle; 1143 tracecmd_curr_thread_handle = handle;
1074 1144
1075 if (handle->cpu_data[cpu].next) 1145 if (handle->cpu_data[cpu].next) {
1146 /* Make sure it's still mapped */
1147 ret = tracecmd_refresh_record(handle, handle->cpu_data[cpu].next);
1148 if (ret < 0) {
1149 free_record(handle->cpu_data[cpu].next);
1150 handle->cpu_data[cpu].next = NULL;
1151 return NULL;
1152 }
1153 /*
1154 * Make sure the index and timestamp are where
1155 * we want them, because the refresh did not update it.
1156 */
1157 if (ret && handle->cpu_data[cpu].timestamp != record->ts) {
1158 handle->cpu_data[cpu].index =
1159 (record->offset & (handle->page_size - 1)) +
1160 record->record_size;
1161 handle->cpu_data[cpu].timestamp = record->ts;
1162 }
1076 return handle->cpu_data[cpu].next; 1163 return handle->cpu_data[cpu].next;
1164 }
1077 1165
1078 if (!page) 1166 if (!page)
1079 return NULL; 1167 return NULL;
@@ -1091,14 +1179,14 @@ read_again:
1091 } 1179 }
1092 1180
1093 if (pevent->old_format) { 1181 if (pevent->old_format) {
1094 data = read_old_format(handle, &ptr, cpu); 1182 record = read_old_format(handle, &ptr, cpu);
1095 if (!data) { 1183 if (!record) {
1096 if (!ptr) 1184 if (!ptr)
1097 return NULL; 1185 return NULL;
1098 goto read_again; 1186 goto read_again;
1099 } 1187 }
1100 1188 record->cpu = cpu;
1101 return data; 1189 return record;
1102 } 1190 }
1103 1191
1104 type_len = translate_data(handle, &ptr, &extend, &length); 1192 type_len = translate_data(handle, &ptr, &extend, &length);
@@ -1121,24 +1209,25 @@ read_again:
1121 1209
1122 handle->cpu_data[cpu].timestamp += extend; 1210 handle->cpu_data[cpu].timestamp += extend;
1123 1211
1124 data = malloc(sizeof(*data)); 1212 record = malloc(sizeof(*record));
1125 if (!data) 1213 if (!record)
1126 return NULL; 1214 return NULL;
1127 memset(data, 0, sizeof(*data)); 1215 memset(record, 0, sizeof(*record));
1128 1216
1129 data->ts = handle->cpu_data[cpu].timestamp; 1217 record->ts = handle->cpu_data[cpu].timestamp;
1130 data->size = length; 1218 record->size = length;
1131 data->data = ptr; 1219 record->cpu = cpu;
1132 data->offset = handle->cpu_data[cpu].offset + index; 1220 record->data = ptr;
1221 record->offset = handle->cpu_data[cpu].offset + index;
1133 1222
1134 ptr += length; 1223 ptr += length;
1135 1224
1136 handle->cpu_data[cpu].index = calc_index(handle, ptr, cpu); 1225 handle->cpu_data[cpu].index = calc_index(handle, ptr, cpu);
1137 handle->cpu_data[cpu].next = data; 1226 handle->cpu_data[cpu].next = record;
1138 1227
1139 data->record_size = handle->cpu_data[cpu].index - index; 1228 record->record_size = handle->cpu_data[cpu].index - index;
1140 1229
1141 return data; 1230 return record;
1142} 1231}
1143 1232
1144/** 1233/**
@@ -1154,12 +1243,12 @@ read_again:
1154struct record * 1243struct record *
1155tracecmd_read_data(struct tracecmd_input *handle, int cpu) 1244tracecmd_read_data(struct tracecmd_input *handle, int cpu)
1156{ 1245{
1157 struct record *data; 1246 struct record *record;
1158 1247
1159 data = tracecmd_peek_data(handle, cpu); 1248 record = tracecmd_peek_data(handle, cpu);
1160 handle->cpu_data[cpu].next = NULL; 1249 handle->cpu_data[cpu].next = NULL;
1161 1250
1162 return data; 1251 return record;
1163} 1252}
1164 1253
1165static int init_read(struct tracecmd_input *handle, int cpu) 1254static int init_read(struct tracecmd_input *handle, int cpu)
diff --git a/trace-read.c b/trace-read.c
index 5a5d4df..a7cac1e 100644
--- a/trace-read.c
+++ b/trace-read.c
@@ -202,7 +202,7 @@ static void show_data(struct tracecmd_input *handle, int cpu)
202 test_save(record, cpu); 202 test_save(record, cpu);
203 203
204 trace_seq_init(&s); 204 trace_seq_init(&s);
205 pevent_print_event(pevent, &s, cpu, record->data, record->size, record->ts); 205 pevent_print_event(pevent, &s, record);
206 trace_seq_do_printf(&s); 206 trace_seq_do_printf(&s);
207 printf("\n"); 207 printf("\n");
208 208
diff --git a/trace-view-store.c b/trace-view-store.c
index eb096fa..9e79a28 100644
--- a/trace-view-store.c
+++ b/trace-view-store.c
@@ -470,7 +470,7 @@ trace_view_store_get_value (GtkTreeModel *tree_model,
470 470
471 case TRACE_VIEW_STORE_COL_LAT: 471 case TRACE_VIEW_STORE_COL_LAT:
472 trace_seq_init(&s); 472 trace_seq_init(&s);
473 pevent_data_lat_fmt(pevent, &s, data->data, data->size); 473 pevent_data_lat_fmt(pevent, &s, data);
474 g_value_set_string(value, s.buffer); 474 g_value_set_string(value, s.buffer);
475 break; 475 break;
476 476
@@ -485,8 +485,7 @@ trace_view_store_get_value (GtkTreeModel *tree_model,
485 485
486 486
487 trace_seq_init(&s); 487 trace_seq_init(&s);
488 pevent_event_info(&s, event, cpu, data->data, data->size, 488 pevent_event_info(&s, event, data);
489 record->timestamp);
490 g_value_set_string(value, s.buffer); 489 g_value_set_string(value, s.buffer);
491 break; 490 break;
492 } 491 }