diff options
-rw-r--r-- | Documentation/trace-cmd-restore.1.txt | 90 | ||||
-rw-r--r-- | Documentation/trace-cmd.1.txt | 3 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | trace-cmd.c | 3 | ||||
-rw-r--r-- | trace-cmd.h | 1 | ||||
-rw-r--r-- | trace-local.h | 2 | ||||
-rw-r--r-- | trace-output.c | 14 | ||||
-rw-r--r-- | trace-restore.c | 146 | ||||
-rw-r--r-- | trace-usage.c | 8 |
9 files changed, 260 insertions, 9 deletions
diff --git a/Documentation/trace-cmd-restore.1.txt b/Documentation/trace-cmd-restore.1.txt new file mode 100644 index 0000000..6fd6ba4 --- /dev/null +++ b/Documentation/trace-cmd-restore.1.txt | |||
@@ -0,0 +1,90 @@ | |||
1 | TRACE-CMD-RESTORE(1) | ||
2 | ==================== | ||
3 | |||
4 | NAME | ||
5 | ---- | ||
6 | trace-cmd-restore - restore a failed trace record | ||
7 | |||
8 | SYNOPSIS | ||
9 | -------- | ||
10 | *trace-cmd restore* ['OPTIONS'] ['command'] cpu-file [cpu-file ...] | ||
11 | |||
12 | DESCRIPTION | ||
13 | ----------- | ||
14 | The trace-cmd(1) restore command will restore a crashed trace-cmd-record(1) | ||
15 | file. If for some reason a trace-cmd record fails, it will leave a the | ||
16 | per-cpu data files and not create the final trace.dat file. The trace-cmd | ||
17 | restore will append the files to create a working trace.dat file that can | ||
18 | be read with trace-cmd-report(1). | ||
19 | |||
20 | When trace-cmd record runs, it spawns off a process per CPU and writes | ||
21 | to a per cpu file usually called 'trace.dat.cpuX', where X represents the | ||
22 | CPU number that it is tracing. If the -o option was used in the trace-cmd | ||
23 | record, then the CPU data files will have that name instead of the | ||
24 | 'trace.dat' name. If a unexpected crash occurs before the tracing | ||
25 | is finished, then the per CPU files will still exist but there will | ||
26 | not be any trace.dat file to read from. trace-cmd restore will allow you | ||
27 | to create a trace.dat file with the existing data files. | ||
28 | |||
29 | OPTIONS | ||
30 | ------- | ||
31 | *-c*:: | ||
32 | Create a partial trace.dat file from the machine, to be used with | ||
33 | a full trace-cmd restore at another time. This option is useful for | ||
34 | embedded devices. If a server contains the cpu files of a crashed | ||
35 | trace-cmd record (or trace-cmd listen), trace-cmd restore can be | ||
36 | executed on the embedded device with the -c option to get all the | ||
37 | stored information of that embedded device. Then the file created | ||
38 | could be copied to the server to run the trace-cmd restore there | ||
39 | with the cpu files. | ||
40 | |||
41 | If *-o* is not specified, then the file created will be called | ||
42 | 'trace-partial.dat'. This is because the file is not a full version | ||
43 | of something that trace-cmd-report(1) could use. | ||
44 | |||
45 | *-o* output':: | ||
46 | By default, trace-cmd restore will create a 'trace.dat' file | ||
47 | (or 'trace-partial.dat' if *-c* is specified). You can | ||
48 | specify a different file to write to with the *-o* option. | ||
49 | |||
50 | *-i* input:: | ||
51 | By default, trace-cmd restore will read the information of the | ||
52 | current system to create the initial data stored in the 'trace.dat' | ||
53 | file. If the crash was on another machine, then that machine should | ||
54 | have the trace-cmd restore run with the *-c* option to create the | ||
55 | trace.dat partial file. Then that file can be copied to the current | ||
56 | machine where trace-cmd restore will use *-i* to load that file | ||
57 | instead of reading from the current system. | ||
58 | |||
59 | EXAMPLES | ||
60 | -------- | ||
61 | |||
62 | If a crash happened on another box, you could run: | ||
63 | |||
64 | $ trace-cmd restore -c -o box-partial.dat | ||
65 | |||
66 | Then on the server that has the cpu files: | ||
67 | |||
68 | $ trace-cmd restore -i box-partial.dat trace.dat.cpu0 trace.dat.cpu1 | ||
69 | |||
70 | This would create a trace.dat file for the embedded box. | ||
71 | |||
72 | SEE ALSO | ||
73 | -------- | ||
74 | trace-cmd(1), trace-cmd-record(1), trace-cmd-report(1), trace-cmd-start(1), | ||
75 | trace-cmd-stop(1), trace-cmd-extract(1), trace-cmd-reset(1), trace-cmd-split(1), | ||
76 | trace-cmd-list(1), trace-cmd-listen(1) | ||
77 | |||
78 | AUTHOR | ||
79 | ------ | ||
80 | Written by Steven Rostedt, <rostedt@goodmis.org> | ||
81 | |||
82 | RESOURCES | ||
83 | --------- | ||
84 | git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git | ||
85 | |||
86 | COPYING | ||
87 | ------- | ||
88 | Copyright \(C) 2010 Red Hat, Inc. Free use of this software is granted under | ||
89 | the terms of the GNU Public License (GPL). | ||
90 | |||
diff --git a/Documentation/trace-cmd.1.txt b/Documentation/trace-cmd.1.txt index fb4cadd..14c543c 100644 --- a/Documentation/trace-cmd.1.txt +++ b/Documentation/trace-cmd.1.txt | |||
@@ -43,6 +43,8 @@ COMMANDS | |||
43 | 43 | ||
44 | listen - open up a port to listen for remote tracing connections. | 44 | listen - open up a port to listen for remote tracing connections. |
45 | 45 | ||
46 | restore - restore the data files of a crashed run of trace-cmd record | ||
47 | |||
46 | 48 | ||
47 | OPTIONS | 49 | OPTIONS |
48 | ------- | 50 | ------- |
@@ -56,6 +58,7 @@ SEE ALSO | |||
56 | -------- | 58 | -------- |
57 | trace-cmd-record(1), trace-cmd-report(1), trace-cmd-start(1), | 59 | trace-cmd-record(1), trace-cmd-report(1), trace-cmd-start(1), |
58 | trace-cmd-stop(1), trace-cmd-extract(1), trace-cmd-reset(1), | 60 | trace-cmd-stop(1), trace-cmd-extract(1), trace-cmd-reset(1), |
61 | trace-cmd-restore(1), | ||
59 | trace-cmd-split(1), trace-cmd-list(1), trace-cmd-listen(1), | 62 | trace-cmd-split(1), trace-cmd-list(1), trace-cmd-listen(1), |
60 | trace-cmd.dat(5) | 63 | trace-cmd.dat(5) |
61 | 64 | ||
@@ -262,7 +262,7 @@ KERNEL_SHARK_OBJS = $(TRACE_VIEW_OBJS) $(TRACE_GRAPH_OBJS) $(TRACE_GUI_OBJS) \ | |||
262 | 262 | ||
263 | PEVENT_LIB_OBJS = parse-events.o trace-seq.o parse-filter.o parse-utils.o | 263 | PEVENT_LIB_OBJS = parse-events.o trace-seq.o parse-filter.o parse-utils.o |
264 | TCMD_LIB_OBJS = $(PEVENT_LIB_OBJS) trace-util.o trace-input.o trace-ftrace.o \ | 264 | TCMD_LIB_OBJS = $(PEVENT_LIB_OBJS) trace-util.o trace-input.o trace-ftrace.o \ |
265 | trace-output.o trace-record.o | 265 | trace-output.o trace-record.o trace-restore.o |
266 | 266 | ||
267 | PLUGIN_OBJS = plugin_hrtimer.o plugin_kmem.o plugin_sched_switch.o \ | 267 | PLUGIN_OBJS = plugin_hrtimer.o plugin_kmem.o plugin_sched_switch.o \ |
268 | plugin_mac80211.o plugin_jbd2.o plugin_function.o | 268 | plugin_mac80211.o plugin_jbd2.o plugin_function.o |
diff --git a/trace-cmd.c b/trace-cmd.c index 7afc5ac..6fbac8c 100644 --- a/trace-cmd.c +++ b/trace-cmd.c | |||
@@ -1429,6 +1429,9 @@ int main (int argc, char **argv) | |||
1429 | } else if (strcmp(argv[1], "split") == 0) { | 1429 | } else if (strcmp(argv[1], "split") == 0) { |
1430 | trace_split(argc, argv); | 1430 | trace_split(argc, argv); |
1431 | exit(0); | 1431 | exit(0); |
1432 | } else if (strcmp(argv[1], "restore") == 0) { | ||
1433 | trace_restore(argc, argv); | ||
1434 | exit(0); | ||
1432 | } else if ((record = (strcmp(argv[1], "record") == 0)) || | 1435 | } else if ((record = (strcmp(argv[1], "record") == 0)) || |
1433 | (strcmp(argv[1], "start") == 0) || | 1436 | (strcmp(argv[1], "start") == 0) || |
1434 | ((extract = strcmp(argv[1], "extract") == 0))) { | 1437 | ((extract = strcmp(argv[1], "extract") == 0))) { |
diff --git a/trace-cmd.h b/trace-cmd.h index d8ebccd..b2586bf 100644 --- a/trace-cmd.h +++ b/trace-cmd.h | |||
@@ -160,6 +160,7 @@ struct tracecmd_output *tracecmd_create_file_latency(const char *output_file, in | |||
160 | struct tracecmd_output *tracecmd_create_file(const char *output_file, | 160 | struct tracecmd_output *tracecmd_create_file(const char *output_file, |
161 | int cpus, char * const *cpu_data_files); | 161 | int cpus, char * const *cpu_data_files); |
162 | struct tracecmd_output *tracecmd_create_init_fd(int fd); | 162 | struct tracecmd_output *tracecmd_create_init_fd(int fd); |
163 | struct tracecmd_output *tracecmd_create_init_file(const char *output_file); | ||
163 | void tracecmd_output_close(struct tracecmd_output *handle); | 164 | void tracecmd_output_close(struct tracecmd_output *handle); |
164 | struct tracecmd_output *tracecmd_copy(struct tracecmd_input *ihandle, | 165 | struct tracecmd_output *tracecmd_copy(struct tracecmd_input *ihandle, |
165 | const char *file); | 166 | const char *file); |
diff --git a/trace-local.h b/trace-local.h index 60b8b5e..0ae798d 100644 --- a/trace-local.h +++ b/trace-local.h | |||
@@ -42,4 +42,6 @@ void trace_split(int argc, char **argv); | |||
42 | 42 | ||
43 | void trace_listen(int argc, char **argv); | 43 | void trace_listen(int argc, char **argv); |
44 | 44 | ||
45 | void trace_restore(int argc, char **argv); | ||
46 | |||
45 | #endif /* __TRACE_LOCAL_H */ | 47 | #endif /* __TRACE_LOCAL_H */ |
diff --git a/trace-output.c b/trace-output.c index c34e8b2..14fe0f1 100644 --- a/trace-output.c +++ b/trace-output.c | |||
@@ -860,16 +860,14 @@ struct tracecmd_output *tracecmd_create_file(const char *output_file, | |||
860 | return handle; | 860 | return handle; |
861 | } | 861 | } |
862 | 862 | ||
863 | struct tracecmd_output * | 863 | struct tracecmd_output *tracecmd_create_init_fd(int fd) |
864 | tracecmd_create_init_fd(int fd) | ||
865 | { | 864 | { |
866 | struct tracecmd_output *handle; | 865 | return create_file_fd(fd, NULL); |
867 | 866 | } | |
868 | handle = create_file_fd(fd, NULL); | ||
869 | if (!handle) | ||
870 | return NULL; | ||
871 | 867 | ||
872 | return handle; | 868 | struct tracecmd_output *tracecmd_create_init_file(const char *output_file) |
869 | { | ||
870 | return create_file(output_file, NULL); | ||
873 | } | 871 | } |
874 | 872 | ||
875 | /** | 873 | /** |
diff --git a/trace-restore.c b/trace-restore.c new file mode 100644 index 0000000..cf8c14f --- /dev/null +++ b/trace-restore.c | |||
@@ -0,0 +1,146 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com> | ||
3 | * | ||
4 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
5 | * | ||
6 | * This program is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; version 2 of the License (not later!) | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
18 | * | ||
19 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
20 | */ | ||
21 | #define _LARGEFILE64_SOURCE | ||
22 | #define _GNU_SOURCE | ||
23 | #include <dirent.h> | ||
24 | #include <stdio.h> | ||
25 | #include <stdlib.h> | ||
26 | #include <string.h> | ||
27 | #include <getopt.h> | ||
28 | #include <stdarg.h> | ||
29 | #include <sys/types.h> | ||
30 | #include <sys/stat.h> | ||
31 | #include <sys/wait.h> | ||
32 | #include <sys/mman.h> | ||
33 | #include <pthread.h> | ||
34 | #include <fcntl.h> | ||
35 | #include <signal.h> | ||
36 | #include <unistd.h> | ||
37 | #include <ctype.h> | ||
38 | #include <errno.h> | ||
39 | |||
40 | #include "trace-local.h" | ||
41 | |||
42 | void trace_restore (int argc, char **argv) | ||
43 | { | ||
44 | struct tracecmd_output *handle; | ||
45 | const char *output_file = "trace.dat"; | ||
46 | const char *output = NULL; | ||
47 | const char *input = NULL; | ||
48 | struct stat st1; | ||
49 | struct stat st2; | ||
50 | int first_arg; | ||
51 | int create_only = 0; | ||
52 | int args; | ||
53 | int c; | ||
54 | |||
55 | if (argc < 2) | ||
56 | usage(argv); | ||
57 | |||
58 | if (strcmp(argv[1], "restore") != 0) | ||
59 | usage(argv); | ||
60 | |||
61 | while ((c = getopt(argc-1, argv+1, "+hco:i:")) >= 0) { | ||
62 | switch (c) { | ||
63 | case 'h': | ||
64 | usage(argv); | ||
65 | break; | ||
66 | case 'c': | ||
67 | if (input) | ||
68 | die("-c and -i are incompatible"); | ||
69 | create_only = 1; | ||
70 | /* make output default to partial */ | ||
71 | output_file = "trace-partial.dat"; | ||
72 | break; | ||
73 | |||
74 | case 'o': | ||
75 | if (output) | ||
76 | die("only one output file allowed"); | ||
77 | output = optarg; | ||
78 | break; | ||
79 | |||
80 | case 'i': | ||
81 | if (input) | ||
82 | die("only one input file allowed"); | ||
83 | if (create_only) | ||
84 | die("-c and -i are incompatible"); | ||
85 | input = optarg; | ||
86 | break; | ||
87 | |||
88 | default: | ||
89 | usage(argv); | ||
90 | } | ||
91 | } | ||
92 | |||
93 | if (!output) | ||
94 | output = output_file; | ||
95 | |||
96 | if ((argc - optind) <= 1) { | ||
97 | if (!create_only) { | ||
98 | warning("No data files found"); | ||
99 | usage(argv); | ||
100 | } | ||
101 | |||
102 | handle = tracecmd_create_init_file(output); | ||
103 | if (!handle) | ||
104 | die("Unabled to create output file %s", output); | ||
105 | tracecmd_output_close(handle); | ||
106 | exit(0); | ||
107 | } | ||
108 | first_arg = optind + 1; | ||
109 | args = argc - first_arg; | ||
110 | printf("first = %d %s args=%d\n", first_arg, argv[first_arg], args); | ||
111 | |||
112 | /* Make sure input and output are not the same file */ | ||
113 | if (input && output) { | ||
114 | if (stat(input, &st1) < 0) | ||
115 | die("%s:", input); | ||
116 | /* output exists? otherwise we don't care */ | ||
117 | if (stat(output, &st2) == 0) { | ||
118 | if (st1.st_ino == st2.st_ino && | ||
119 | st1.st_dev == st2.st_dev) | ||
120 | die("input and output file are the same"); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | if (input) { | ||
125 | struct tracecmd_input *ihandle; | ||
126 | |||
127 | ihandle = tracecmd_alloc(input); | ||
128 | if (!ihandle) | ||
129 | die("error reading file %s", input); | ||
130 | /* make sure headers are ok */ | ||
131 | if (tracecmd_read_headers(ihandle) < 0) | ||
132 | die("error reading file %s headers", input); | ||
133 | |||
134 | handle = tracecmd_copy(ihandle, output); | ||
135 | tracecmd_close(ihandle); | ||
136 | } else | ||
137 | handle = tracecmd_create_init_file(output); | ||
138 | |||
139 | if (!handle) | ||
140 | die("error writing to %s", output); | ||
141 | |||
142 | if (tracecmd_append_cpu_data(handle, args, &argv[first_arg]) < 0) | ||
143 | die("failed to append data"); | ||
144 | |||
145 | return; | ||
146 | } | ||
diff --git a/trace-usage.c b/trace-usage.c index 8f70f29..5dd691c 100644 --- a/trace-usage.c +++ b/trace-usage.c | |||
@@ -123,6 +123,14 @@ static struct usage_help usage_help[] = { | |||
123 | " -o list available options\n" | 123 | " -o list available options\n" |
124 | }, | 124 | }, |
125 | { | 125 | { |
126 | "restore", | ||
127 | "restore a crashed record", | ||
128 | " %s restore [-c][-o file][-i file] cpu-file [cpu-file ...]\n" | ||
129 | " -c create a partial trace.dat file only\n" | ||
130 | " -o output file\n" | ||
131 | " -i parital trace.dat file for input\n" | ||
132 | }, | ||
133 | { | ||
126 | NULL, NULL, NULL | 134 | NULL, NULL, NULL |
127 | } | 135 | } |
128 | }; | 136 | }; |