aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2010-10-04 09:30:29 -0400
committerSteven Rostedt <rostedt@goodmis.org>2010-10-04 21:15:32 -0400
commit087ef940eac18e561078e09b20e9e3cdb22ad9ff (patch)
treeaf0ebfbf16350347cff9862de596aa372c9250b9
parent84d78973993710e0964aa801d5dcf1b5c4690216 (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.txt45
-rw-r--r--Makefile3
-rw-r--r--trace-cmd.c19
-rw-r--r--trace-cmd.h3
-rw-r--r--trace-local.h2
-rw-r--r--trace-stack.c224
-rw-r--r--trace-usage.c8
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 @@
1TRACE-CMD-STACK(1)
2==================
3
4NAME
5----
6trace-cmd-stack - read, enable or disable Ftrace Linux kernel stack tracing.
7
8SYNOPSIS
9--------
10*trace-cmd stack*
11
12DESCRIPTION
13-----------
14The trace-cmd(1) stack enables the Ftrace stack tracer within the kernel.
15The stack tracer enables the function tracer and at each function call
16within the kernel, the stack is checked. When a new maximum usage stack
17is discovered, it is recorded.
18
19When no option is used, the current stack is displayed.
20
21To enable the stack tracer, use the option *--start*, and to disable
22the stack tracer, use the option *--stop*. The output will be the maximum
23stack found since the start was enabled.
24
25Use *--reset* to reset the stack counter to zero.
26
27SEE ALSO
28--------
29trace-cmd(1), trace-cmd-record(1), trace-cmd-report(1), trace-cmd-start(1),
30trace-cmd-extract(1), trace-cmd-reset(1), trace-cmd-split(1),
31trace-cmd-list(1), trace-cmd-listen(1)
32
33AUTHOR
34------
35Written by Steven Rostedt, <rostedt@goodmis.org>
36
37RESOURCES
38---------
39git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/trace-cmd.git
40
41COPYING
42-------
43Copyright \(C) 2010 Red Hat, Inc. Free use of this software is granted under
44the terms of the GNU Public License (GPL).
45
diff --git a/Makefile b/Makefile
index fe34d1c..41f0d43 100644
--- a/Makefile
+++ b/Makefile
@@ -261,7 +261,8 @@ $(obj)/%.o: $(src)/%.c
261 261
262TRACE_GUI_OBJS = trace-filter.o trace-compat.o trace-hash.o trace-dialog.o \ 262TRACE_GUI_OBJS = trace-filter.o trace-compat.o trace-hash.o trace-dialog.o \
263 trace-xml.o 263 trace-xml.o
264TRACE_CMD_OBJS = trace-cmd.o trace-usage.o trace-read.o trace-split.o trace-listen.o 264TRACE_CMD_OBJS = trace-cmd.o trace-usage.o trace-read.o trace-split.o trace-listen.o \
265 trace-stack.o
265TRACE_VIEW_OBJS = trace-view.o trace-view-store.o 266TRACE_VIEW_OBJS = trace-view.o trace-view-store.o
266TRACE_GRAPH_OBJS = trace-graph.o trace-plot.o trace-plot-cpu.o trace-plot-task.o 267TRACE_GRAPH_OBJS = trace-graph.o trace-plot.o trace-plot-cpu.o trace-plot-task.o
267TRACE_VIEW_MAIN_OBJS = trace-view-main.o $(TRACE_VIEW_OBJS) $(TRACE_GUI_OBJS) 268TRACE_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 @@
55int silence_warnings; 55int silence_warnings;
56int show_status; 56int show_status;
57 57
58static char *get_tracing_file(const char *name);
59static void put_tracing_file(char *file);
60
61char *tracecmd_get_tracing_file(const char *name)
62{
63 return get_tracing_file(name);
64}
65
66void tracecmd_put_tracing_file(char *name)
67{
68 put_tracing_file(name);
69}
70
58static int tracing_on_init_val; 71static int tracing_on_init_val;
59 72
60static int rt_prio; 73static int rt_prio;
@@ -286,9 +299,6 @@ static int set_ftrace(int set)
286 return 0; 299 return 0;
287} 300}
288 301
289static char *get_tracing_file(const char *name);
290static void put_tracing_file(char *file);
291
292static void clear_trace(void) 302static 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);
149int tracecmd_ftrace_overrides(struct tracecmd_input *handle, struct tracecmd_ftrace *finfo); 149int tracecmd_ftrace_overrides(struct tracecmd_input *handle, struct tracecmd_ftrace *finfo);
150struct pevent *tracecmd_get_pevent(struct tracecmd_input *handle); 150struct pevent *tracecmd_get_pevent(struct tracecmd_input *handle);
151 151
152char *tracecmd_get_tracing_file(const char *name);
153void 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 */
154extern __thread struct tracecmd_input *tracecmd_curr_thread_handle; 157extern __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
45void trace_restore(int argc, char **argv); 45void trace_restore(int argc, char **argv);
46 46
47void 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
37enum stack_type {
38 STACK_START,
39 STACK_STOP,
40 STACK_RESET,
41 STACK_REPORT
42};
43
44static 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
54static 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
71static 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
91static void start_trace(void)
92{
93 start_stop_trace('1');
94}
95
96static void stop_trace(void)
97{
98 start_stop_trace('0');
99}
100
101static 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
121static 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
156void 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};