diff options
| author | Steven Rostedt <srostedt@redhat.com> | 2010-10-04 09:30:29 -0400 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2010-10-04 21:15:32 -0400 |
| commit | 087ef940eac18e561078e09b20e9e3cdb22ad9ff (patch) | |
| tree | af0ebfbf16350347cff9862de596aa372c9250b9 | |
| parent | 84d78973993710e0964aa801d5dcf1b5c4690216 (diff) | |
trace-cmd: Added trace stack command
Added the command "trace-cmd stack" to run the stack tracer.
It simply enables the stack tracer and depending on the options
it will ouput the current stack, or disable it.
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
| -rw-r--r-- | Documentation/trace-cmd-stack.1.txt | 45 | ||||
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | trace-cmd.c | 19 | ||||
| -rw-r--r-- | trace-cmd.h | 3 | ||||
| -rw-r--r-- | trace-local.h | 2 | ||||
| -rw-r--r-- | trace-stack.c | 224 | ||||
| -rw-r--r-- | trace-usage.c | 8 |
7 files changed, 300 insertions, 4 deletions
diff --git a/Documentation/trace-cmd-stack.1.txt b/Documentation/trace-cmd-stack.1.txt new file mode 100644 index 0000000..6b5f0c0 --- /dev/null +++ b/Documentation/trace-cmd-stack.1.txt | |||
| @@ -0,0 +1,45 @@ | |||
| 1 | TRACE-CMD-STACK(1) | ||
| 2 | ================== | ||
| 3 | |||
| 4 | NAME | ||
| 5 | ---- | ||
| 6 | trace-cmd-stack - read, enable or disable Ftrace Linux kernel stack tracing. | ||
| 7 | |||
| 8 | SYNOPSIS | ||
| 9 | -------- | ||
| 10 | *trace-cmd stack* | ||
| 11 | |||
| 12 | DESCRIPTION | ||
| 13 | ----------- | ||
| 14 | The trace-cmd(1) stack enables the Ftrace stack tracer within the kernel. | ||
| 15 | The stack tracer enables the function tracer and at each function call | ||
| 16 | within the kernel, the stack is checked. When a new maximum usage stack | ||
| 17 | is discovered, it is recorded. | ||
| 18 | |||
| 19 | When no option is used, the current stack is displayed. | ||
| 20 | |||
| 21 | To enable the stack tracer, use the option *--start*, and to disable | ||
| 22 | the stack tracer, use the option *--stop*. The output will be the maximum | ||
| 23 | stack found since the start was enabled. | ||
| 24 | |||
| 25 | Use *--reset* to reset the stack counter to zero. | ||
| 26 | |||
| 27 | SEE ALSO | ||
| 28 | -------- | ||
| 29 | trace-cmd(1), trace-cmd-record(1), trace-cmd-report(1), trace-cmd-start(1), | ||
| 30 | trace-cmd-extract(1), trace-cmd-reset(1), trace-cmd-split(1), | ||
| 31 | trace-cmd-list(1), trace-cmd-listen(1) | ||
| 32 | |||
| 33 | AUTHOR | ||
| 34 | ------ | ||
| 35 | Written by Steven Rostedt, <rostedt@goodmis.org> | ||
| 36 | |||
| 37 | RESOURCES | ||
| 38 | --------- | ||
| 39 | git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git | ||
| 40 | |||
| 41 | COPYING | ||
| 42 | ------- | ||
| 43 | Copyright \(C) 2010 Red Hat, Inc. Free use of this software is granted under | ||
| 44 | the terms of the GNU Public License (GPL). | ||
| 45 | |||
| @@ -261,7 +261,8 @@ $(obj)/%.o: $(src)/%.c | |||
| 261 | 261 | ||
| 262 | TRACE_GUI_OBJS = trace-filter.o trace-compat.o trace-hash.o trace-dialog.o \ | 262 | TRACE_GUI_OBJS = trace-filter.o trace-compat.o trace-hash.o trace-dialog.o \ |
| 263 | trace-xml.o | 263 | trace-xml.o |
| 264 | TRACE_CMD_OBJS = trace-cmd.o trace-usage.o trace-read.o trace-split.o trace-listen.o | 264 | TRACE_CMD_OBJS = trace-cmd.o trace-usage.o trace-read.o trace-split.o trace-listen.o \ |
| 265 | trace-stack.o | ||
| 265 | TRACE_VIEW_OBJS = trace-view.o trace-view-store.o | 266 | TRACE_VIEW_OBJS = trace-view.o trace-view-store.o |
| 266 | TRACE_GRAPH_OBJS = trace-graph.o trace-plot.o trace-plot-cpu.o trace-plot-task.o | 267 | TRACE_GRAPH_OBJS = trace-graph.o trace-plot.o trace-plot-cpu.o trace-plot-task.o |
| 267 | TRACE_VIEW_MAIN_OBJS = trace-view-main.o $(TRACE_VIEW_OBJS) $(TRACE_GUI_OBJS) | 268 | TRACE_VIEW_MAIN_OBJS = trace-view-main.o $(TRACE_VIEW_OBJS) $(TRACE_GUI_OBJS) |
diff --git a/trace-cmd.c b/trace-cmd.c index cce499a..9cbe362 100644 --- a/trace-cmd.c +++ b/trace-cmd.c | |||
| @@ -55,6 +55,19 @@ | |||
| 55 | int silence_warnings; | 55 | int silence_warnings; |
| 56 | int show_status; | 56 | int show_status; |
| 57 | 57 | ||
| 58 | static char *get_tracing_file(const char *name); | ||
| 59 | static void put_tracing_file(char *file); | ||
| 60 | |||
| 61 | char *tracecmd_get_tracing_file(const char *name) | ||
| 62 | { | ||
| 63 | return get_tracing_file(name); | ||
| 64 | } | ||
| 65 | |||
| 66 | void tracecmd_put_tracing_file(char *name) | ||
| 67 | { | ||
| 68 | put_tracing_file(name); | ||
| 69 | } | ||
| 70 | |||
| 58 | static int tracing_on_init_val; | 71 | static int tracing_on_init_val; |
| 59 | 72 | ||
| 60 | static int rt_prio; | 73 | static int rt_prio; |
| @@ -286,9 +299,6 @@ static int set_ftrace(int set) | |||
| 286 | return 0; | 299 | return 0; |
| 287 | } | 300 | } |
| 288 | 301 | ||
| 289 | static char *get_tracing_file(const char *name); | ||
| 290 | static void put_tracing_file(char *file); | ||
| 291 | |||
| 292 | static void clear_trace(void) | 302 | static void clear_trace(void) |
| 293 | { | 303 | { |
| 294 | FILE *fp; | 304 | FILE *fp; |
| @@ -1439,6 +1449,9 @@ int main (int argc, char **argv) | |||
| 1439 | } else if (strcmp(argv[1], "restore") == 0) { | 1449 | } else if (strcmp(argv[1], "restore") == 0) { |
| 1440 | trace_restore(argc, argv); | 1450 | trace_restore(argc, argv); |
| 1441 | exit(0); | 1451 | exit(0); |
| 1452 | } else if (strcmp(argv[1], "stack") == 0) { | ||
| 1453 | trace_stack(argc, argv); | ||
| 1454 | exit(0); | ||
| 1442 | } else if ((record = (strcmp(argv[1], "record") == 0)) || | 1455 | } else if ((record = (strcmp(argv[1], "record") == 0)) || |
| 1443 | (strcmp(argv[1], "start") == 0) || | 1456 | (strcmp(argv[1], "start") == 0) || |
| 1444 | ((extract = strcmp(argv[1], "extract") == 0))) { | 1457 | ((extract = strcmp(argv[1], "extract") == 0))) { |
diff --git a/trace-cmd.h b/trace-cmd.h index b77b8e6..59d9d54 100644 --- a/trace-cmd.h +++ b/trace-cmd.h | |||
| @@ -149,6 +149,9 @@ tracecmd_get_cursor(struct tracecmd_input *handle, int cpu); | |||
| 149 | int tracecmd_ftrace_overrides(struct tracecmd_input *handle, struct tracecmd_ftrace *finfo); | 149 | int tracecmd_ftrace_overrides(struct tracecmd_input *handle, struct tracecmd_ftrace *finfo); |
| 150 | struct pevent *tracecmd_get_pevent(struct tracecmd_input *handle); | 150 | struct pevent *tracecmd_get_pevent(struct tracecmd_input *handle); |
| 151 | 151 | ||
| 152 | char *tracecmd_get_tracing_file(const char *name); | ||
| 153 | void tracecmd_put_tracing_file(char *name); | ||
| 154 | |||
| 152 | #ifndef SWIG | 155 | #ifndef SWIG |
| 153 | /* hack for function graph work around */ | 156 | /* hack for function graph work around */ |
| 154 | extern __thread struct tracecmd_input *tracecmd_curr_thread_handle; | 157 | extern __thread struct tracecmd_input *tracecmd_curr_thread_handle; |
diff --git a/trace-local.h b/trace-local.h index 0ae798d..73c38d2 100644 --- a/trace-local.h +++ b/trace-local.h | |||
| @@ -44,4 +44,6 @@ void trace_listen(int argc, char **argv); | |||
| 44 | 44 | ||
| 45 | void trace_restore(int argc, char **argv); | 45 | void trace_restore(int argc, char **argv); |
| 46 | 46 | ||
| 47 | void trace_stack(int argc, char **argv); | ||
| 48 | |||
| 47 | #endif /* __TRACE_LOCAL_H */ | 49 | #endif /* __TRACE_LOCAL_H */ |
diff --git a/trace-stack.c b/trace-stack.c new file mode 100644 index 0000000..3d9f392 --- /dev/null +++ b/trace-stack.c | |||
| @@ -0,0 +1,224 @@ | |||
| 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 _GNU_SOURCE | ||
| 22 | #include <stdio.h> | ||
| 23 | #include <stdlib.h> | ||
| 24 | #include <string.h> | ||
| 25 | #include <getopt.h> | ||
| 26 | #include <sys/types.h> | ||
| 27 | #include <sys/stat.h> | ||
| 28 | #include <sys/wait.h> | ||
| 29 | #include <fcntl.h> | ||
| 30 | #include <unistd.h> | ||
| 31 | #include <errno.h> | ||
| 32 | |||
| 33 | #include "trace-local.h" | ||
| 34 | |||
| 35 | #define PROC_FILE "/proc/sys/kernel/stack_tracer_enabled" | ||
| 36 | |||
| 37 | enum stack_type { | ||
| 38 | STACK_START, | ||
| 39 | STACK_STOP, | ||
| 40 | STACK_RESET, | ||
| 41 | STACK_REPORT | ||
| 42 | }; | ||
| 43 | |||
| 44 | static void test_available(void) | ||
| 45 | { | ||
| 46 | struct stat buf; | ||
| 47 | int fd; | ||
| 48 | |||
| 49 | fd = stat(PROC_FILE, &buf); | ||
| 50 | if (fd < 0) | ||
| 51 | die("stack tracer not configured on running kernel"); | ||
| 52 | } | ||
| 53 | |||
| 54 | static char read_proc(void) | ||
| 55 | { | ||
| 56 | char buf[1]; | ||
| 57 | int fd; | ||
| 58 | int n; | ||
| 59 | |||
| 60 | fd = open(PROC_FILE, O_RDONLY); | ||
| 61 | if (fd < 0) | ||
| 62 | die("reading %s", PROC_FILE); | ||
| 63 | n = read(fd, buf, 1); | ||
| 64 | close(fd); | ||
| 65 | if (n != 1) | ||
| 66 | die("error reading %s", PROC_FILE); | ||
| 67 | |||
| 68 | return buf[0]; | ||
| 69 | } | ||
| 70 | |||
| 71 | static void start_stop_trace(char val) | ||
| 72 | { | ||
| 73 | char buf[1]; | ||
| 74 | int fd; | ||
| 75 | int n; | ||
| 76 | |||
| 77 | buf[0] = read_proc(); | ||
| 78 | if (buf[0] == val) | ||
| 79 | return; | ||
| 80 | |||
| 81 | fd = open(PROC_FILE, O_WRONLY); | ||
| 82 | if (fd < 0) | ||
| 83 | die("writing %s", PROC_FILE); | ||
| 84 | buf[0] = val; | ||
| 85 | n = write(fd, buf, 1); | ||
| 86 | if (n < 0) | ||
| 87 | die("writing into %s", PROC_FILE); | ||
| 88 | close(fd); | ||
| 89 | } | ||
| 90 | |||
| 91 | static void start_trace(void) | ||
| 92 | { | ||
| 93 | start_stop_trace('1'); | ||
| 94 | } | ||
| 95 | |||
| 96 | static void stop_trace(void) | ||
| 97 | { | ||
| 98 | start_stop_trace('0'); | ||
| 99 | } | ||
| 100 | |||
| 101 | static void reset_trace(void) | ||
| 102 | { | ||
| 103 | char *path; | ||
| 104 | char buf[1]; | ||
| 105 | int fd; | ||
| 106 | int n; | ||
| 107 | |||
| 108 | path = tracecmd_get_tracing_file("stack_max_size"); | ||
| 109 | fd = open(path, O_WRONLY); | ||
| 110 | if (fd < 0) | ||
| 111 | die("writing %s", path); | ||
| 112 | |||
| 113 | buf[0] = '0'; | ||
| 114 | n = write(fd, buf, 1); | ||
| 115 | if (n < 0) | ||
| 116 | die("writing into %s", path); | ||
| 117 | tracecmd_put_tracing_file(path); | ||
| 118 | close(fd); | ||
| 119 | } | ||
| 120 | |||
| 121 | static void read_trace(void) | ||
| 122 | { | ||
| 123 | FILE *fp; | ||
| 124 | char *path; | ||
| 125 | char *buf = NULL; | ||
| 126 | size_t n; | ||
| 127 | int r; | ||
| 128 | |||
| 129 | if (read_proc() == '1') | ||
| 130 | printf("(stack tracer running)\n"); | ||
| 131 | else | ||
| 132 | printf("(stack tracer not running)\n"); | ||
| 133 | |||
| 134 | path = tracecmd_get_tracing_file("stack_trace"); | ||
| 135 | fp = fopen(path, "r"); | ||
| 136 | if (!fp) | ||
| 137 | die("reading to '%s'", path); | ||
| 138 | tracecmd_put_tracing_file(path); | ||
| 139 | |||
| 140 | while ((r = getline(&buf, &n, fp)) >= 0) { | ||
| 141 | /* | ||
| 142 | * Skip any line that starts with a '#'. | ||
| 143 | * Those talk about how to enable stack tracing | ||
| 144 | * within the debugfs system. We don't care about that. | ||
| 145 | */ | ||
| 146 | if (buf[0] != '#') | ||
| 147 | printf("%s", buf); | ||
| 148 | |||
| 149 | free(buf); | ||
| 150 | buf = NULL; | ||
| 151 | } | ||
| 152 | |||
| 153 | fclose(fp); | ||
| 154 | } | ||
| 155 | |||
| 156 | void trace_stack (int argc, char **argv) | ||
| 157 | { | ||
| 158 | enum stack_type trace_type = STACK_REPORT; | ||
| 159 | int c; | ||
| 160 | |||
| 161 | if (argc < 2) | ||
| 162 | usage(argv); | ||
| 163 | |||
| 164 | if (strcmp(argv[1], "stack") != 0) | ||
| 165 | usage(argv); | ||
| 166 | |||
| 167 | for (;;) { | ||
| 168 | int option_index = 0; | ||
| 169 | static struct option long_options[] = { | ||
| 170 | {"start", no_argument, NULL, 0}, | ||
| 171 | {"stop", no_argument, NULL, 0}, | ||
| 172 | {"reset", no_argument, NULL, 0}, | ||
| 173 | {"help", no_argument, NULL, '?'}, | ||
| 174 | {NULL, 0, NULL, 0} | ||
| 175 | }; | ||
| 176 | |||
| 177 | c = getopt_long (argc-1, argv+1, "+h?", | ||
| 178 | long_options, &option_index); | ||
| 179 | if (c == -1) | ||
| 180 | break; | ||
| 181 | |||
| 182 | switch (c) { | ||
| 183 | case 'h': | ||
| 184 | usage(argv); | ||
| 185 | break; | ||
| 186 | case 0: | ||
| 187 | switch(option_index) { | ||
| 188 | case 0: | ||
| 189 | trace_type = STACK_START; | ||
| 190 | break; | ||
| 191 | case 1: | ||
| 192 | trace_type = STACK_STOP; | ||
| 193 | break; | ||
| 194 | case 2: | ||
| 195 | trace_type = STACK_RESET; | ||
| 196 | break; | ||
| 197 | default: | ||
| 198 | usage(argv); | ||
| 199 | } | ||
| 200 | break; | ||
| 201 | default: | ||
| 202 | usage(argv); | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | test_available(); | ||
| 207 | |||
| 208 | switch (trace_type) { | ||
| 209 | case STACK_START: | ||
| 210 | start_trace(); | ||
| 211 | break; | ||
| 212 | case STACK_STOP: | ||
| 213 | stop_trace(); | ||
| 214 | break; | ||
| 215 | case STACK_RESET: | ||
| 216 | reset_trace(); | ||
| 217 | break; | ||
| 218 | default: | ||
| 219 | read_trace(); | ||
| 220 | break; | ||
| 221 | } | ||
| 222 | |||
| 223 | return; | ||
| 224 | } | ||
diff --git a/trace-usage.c b/trace-usage.c index 5dd691c..a6280e8 100644 --- a/trace-usage.c +++ b/trace-usage.c | |||
| @@ -131,6 +131,14 @@ static struct usage_help usage_help[] = { | |||
| 131 | " -i parital trace.dat file for input\n" | 131 | " -i parital trace.dat file for input\n" |
| 132 | }, | 132 | }, |
| 133 | { | 133 | { |
| 134 | "stack", | ||
| 135 | "output, enable or disable kernel stack tracing", | ||
| 136 | " %s stack [--start][--stop][--reset]\n" | ||
| 137 | " --start enable the stack tracer\n" | ||
| 138 | " --stop disable the stack tracer\n" | ||
| 139 | " --reset reset the maximum stack found\n" | ||
| 140 | }, | ||
| 141 | { | ||
| 134 | NULL, NULL, NULL | 142 | NULL, NULL, NULL |
| 135 | } | 143 | } |
| 136 | }; | 144 | }; |
