diff options
| author | Steven Rostedt <srostedt@redhat.com> | 2009-12-18 13:32:10 -0500 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2009-12-18 13:38:29 -0500 |
| commit | 8e5898fc7498693cab0b153eea5e37b302e307d2 (patch) | |
| tree | 54bc25ec88b48a6214126b13d993bd901d7e732f | |
| parent | 40a8521b53435a97e855c7d65486da41b30f9131 (diff) | |
| parent | b05f27dc7d0dab346e20795ce4d9f6d56d3e18ea (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.c | 25 | ||||
| -rw-r--r-- | parse-events.h | 12 | ||||
| -rw-r--r-- | plugin_hrtimer.c | 13 | ||||
| -rw-r--r-- | plugin_mac80211.c | 14 | ||||
| -rw-r--r-- | plugin_sched_switch.c | 12 | ||||
| -rw-r--r-- | trace-cmd.c | 138 | ||||
| -rw-r--r-- | trace-cmd.h | 2 | ||||
| -rw-r--r-- | trace-ftrace.c | 55 | ||||
| -rw-r--r-- | trace-graph.c | 8 | ||||
| -rw-r--r-- | trace-input.c | 151 | ||||
| -rw-r--r-- | trace-read.c | 2 | ||||
| -rw-r--r-- | trace-view-store.c | 5 |
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 | */ |
| 3115 | void pevent_data_lat_fmt(struct pevent *pevent, | 3115 | void 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 | */ |
| 3217 | void pevent_event_info(struct trace_seq *s, struct event_format *event, | 3218 | void 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 | ||
| 3228 | void pevent_print_event(struct pevent *pevent, struct trace_seq *s, | 3229 | void 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; | |||
| 61 | struct event_format; | 62 | struct event_format; |
| 62 | 63 | ||
| 63 | typedef int (*pevent_event_handler_func)(struct trace_seq *s, | 64 | typedef 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 | ||
| 68 | typedef int (*pevent_plugin_load_func)(struct pevent *pevent); | 68 | typedef int (*pevent_plugin_load_func)(struct pevent *pevent); |
| 69 | 69 | ||
| @@ -350,7 +350,7 @@ int pevent_register_print_string(struct pevent *pevent, char *fmt, | |||
| 350 | int pevent_pid_is_registered(struct pevent *pevent, int pid); | 350 | int pevent_pid_is_registered(struct pevent *pevent, int pid); |
| 351 | 351 | ||
| 352 | void pevent_print_event(struct pevent *pevent, struct trace_seq *s, | 352 | void 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 | ||
| 355 | int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size); | 355 | int pevent_parse_header_page(struct pevent *pevent, char *buf, unsigned long size); |
| 356 | 356 | ||
| @@ -374,13 +374,13 @@ struct event_format * | |||
| 374 | pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name); | 374 | pevent_find_event_by_name(struct pevent *pevent, const char *sys, const char *name); |
| 375 | 375 | ||
| 376 | void pevent_data_lat_fmt(struct pevent *pevent, | 376 | void 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); |
| 378 | int pevent_data_type(struct pevent *pevent, struct record *rec); | 378 | int pevent_data_type(struct pevent *pevent, struct record *rec); |
| 379 | struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type); | 379 | struct event_format *pevent_data_event_from_type(struct pevent *pevent, int type); |
| 380 | int pevent_data_pid(struct pevent *pevent, struct record *rec); | 380 | int pevent_data_pid(struct pevent *pevent, struct record *rec); |
| 381 | const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid); | 381 | const char *pevent_data_comm_from_pid(struct pevent *pevent, int pid); |
| 382 | void pevent_event_info(struct trace_seq *s, struct event_format *event, | 382 | void 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 | ||
| 385 | struct event_format **pevent_list_events(struct pevent *pevent, enum event_sort_type); | 385 | struct 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 | ||
| 33 | static int timer_expire_handler(struct trace_seq *s, void *data, int size, | 33 | static 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 | ||
| 49 | static int timer_start_handler(struct trace_seq *s, void *data, int size, | 50 | static 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 | ||
| 148 | static int drv_bss_info_changed(struct trace_seq *s, void *data, int size, | 148 | static 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 | ||
| 175 | static int drv_config(struct trace_seq *s, void *data, | 176 | static 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 | ||
| 50 | static int sched_wakeup_handler(struct trace_seq *s, void *data, int size, | 50 | static 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 | ||
| 105 | static int sched_switch_handler(struct trace_seq *s, void *data, int size, | 105 | static 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 | ||
| 148 | static 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 | |||
| 148 | void die(char *fmt, ...) | 161 | void 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 | ||
| 585 | static void flush(int sig) | ||
| 586 | { | ||
| 587 | if (recorder) | ||
| 588 | tracecmd_stop_recording(recorder); | ||
| 589 | } | ||
| 590 | |||
| 572 | static int create_recorder(int cpu) | 591 | static 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 | ||
| 668 | static 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 | |||
| 647 | void usage(char **argv) | 708 | void 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 * | |||
| 72 | tracecmd_read_cpu_first(struct tracecmd_input *handle, int cpu); | 72 | tracecmd_read_cpu_first(struct tracecmd_input *handle, int cpu); |
| 73 | struct record * | 73 | struct record * |
| 74 | tracecmd_read_cpu_last(struct tracecmd_input *handle, int cpu); | 74 | tracecmd_read_cpu_last(struct tracecmd_input *handle, int cpu); |
| 75 | int tracecmd_refresh_record(struct tracecmd_input *handle, | ||
| 76 | struct record *record); | ||
| 75 | 77 | ||
| 76 | int tracecmd_set_cpu_to_timestamp(struct tracecmd_input *handle, | 78 | int 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 | ||
| 31 | static int function_handler(struct trace_seq *s, void *data, int size, | 31 | static 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 | ||
| 222 | static int | 222 | static int |
| 223 | fgraph_ent_handler(struct trace_seq *s, void *data, int size, | 223 | fgraph_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 | ||
| 260 | static int | 287 | static int |
| 261 | fgraph_ret_handler(struct trace_seq *s, void *data, int size, | 288 | fgraph_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 | ||
| 293 | static int | 320 | static int |
| 294 | trace_stack_handler(struct trace_seq *s, void *data, int size, | 321 | trace_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 | ||
| 498 | static unsigned int read_type_len_ts(struct tracecmd_input *handle, void *ptr) | ||
| 499 | { | ||
| 500 | return data2host4(handle->pevent, ptr); | ||
| 501 | } | ||
| 502 | |||
| 498 | static int calc_index(struct tracecmd_input *handle, | 503 | static 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 | */ | ||
| 577 | static int get_page(struct tracecmd_input *handle, int cpu, | 589 | static 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 | */ | ||
| 849 | int 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 * | |||
| 1020 | tracecmd_translate_data(struct tracecmd_input *handle, | 1089 | tracecmd_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 * | |||
| 1061 | tracecmd_peek_data(struct tracecmd_input *handle, int cpu) | 1130 | tracecmd_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: | |||
| 1154 | struct record * | 1243 | struct record * |
| 1155 | tracecmd_read_data(struct tracecmd_input *handle, int cpu) | 1244 | tracecmd_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 | ||
| 1165 | static int init_read(struct tracecmd_input *handle, int cpu) | 1254 | static 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 | } |
