diff options
| author | Steven Rostedt <srostedt@redhat.com> | 2010-09-13 17:09:11 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2010-09-13 21:58:34 -0400 |
| commit | d9016d161fcc776654d1997cf8e8a53ac5a3fc38 (patch) | |
| tree | d9ea91aa06061bc7d1198de5ff252b53435117fa | |
| parent | c5c11fdf5eaf5caa5cd2452f5a8d058106c11db3 (diff) | |
trace-cmd: Add trace-cmd restore
The restore feature now allows you to make a trace.dat file from
several trace.dat.cpu.X files. This will let you put together files
leftover from a crashed trace-cmd record run.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
| -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 | }; |
