aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2011-03-11 16:52:40 -0500
committerSteven Rostedt <rostedt@goodmis.org>2011-03-11 16:52:40 -0500
commitdf843687135e7ffca2d6b70ca5453698e4067bf0 (patch)
tree584312fc355d46a9176d7a7c803ef884e508936f
parent46a183d56259978644643643bea126972333a476 (diff)
trace-cmd: Add --func-stack option to enable function stack trace
Added --func-stack option to trace-cmd record, that will enable the function stack tracing, but only if the -l option (limit functions) is used, and succeeds in filtering functions. It is known that running the function stack trace on all functions can livelock the machine. The output now looks like this: <idle>-0 [002] 64003.696572: function: schedule <idle>-0 [002] 64003.696577: kernel_stack: <stack trace> => cpu_idle (ffffffff8100a38c) => start_secondary (ffffffff814ab828) trace-cmd-4132 [003] 64003.696632: function: schedule trace-cmd-4132 [003] 64003.696637: kernel_stack: <stack trace> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r--Documentation/trace-cmd-record.1.txt7
-rw-r--r--trace-record.c59
-rw-r--r--trace-usage.c2
3 files changed, 67 insertions, 1 deletions
diff --git a/Documentation/trace-cmd-record.1.txt b/Documentation/trace-cmd-record.1.txt
index 87e4f97..b78182a 100644
--- a/Documentation/trace-cmd-record.1.txt
+++ b/Documentation/trace-cmd-record.1.txt
@@ -64,6 +64,13 @@ OPTIONS
64=> cpu_idle (ffffffff8100a38c) 64=> cpu_idle (ffffffff8100a38c)
65=> start_secondary (ffffffff814ab828) 65=> start_secondary (ffffffff814ab828)
66 66
67*--func-stack*::
68 Enable a stack trace on all functions. Note this is only applicable
69 for the "function" plugin tracer, and will only take effect if the
70 -l option is used and succeeds in limiting functions. If the function
71 tracer is not filtered, and the stack trace is enabled, you can live
72 lock the machine.
73
67*-f* 'filter':: 74*-f* 'filter'::
68 Specify a filter for the previous event. This must come after a *-e*. This 75 Specify a filter for the previous event. This must come after a *-e*. This
69 will filter what events get recorded based on the content of the event. 76 will filter what events get recorded based on the content of the event.
diff --git a/trace-record.c b/trace-record.c
index 2a6872c..031e084 100644
--- a/trace-record.c
+++ b/trace-record.c
@@ -54,6 +54,7 @@
54#define ITER_CTRL "trace_options" 54#define ITER_CTRL "trace_options"
55#define MAX_LATENCY "tracing_max_latency" 55#define MAX_LATENCY "tracing_max_latency"
56#define STAMP "stamp" 56#define STAMP "stamp"
57#define FUNC_STACK_TRACE "func_stack_trace"
57 58
58#define UDP_MAX_PACKET (65536 - 20) 59#define UDP_MAX_PACKET (65536 - 20)
59 60
@@ -97,6 +98,8 @@ static struct func_list *filter_funcs;
97static struct func_list *notrace_funcs; 98static struct func_list *notrace_funcs;
98static struct func_list *graph_funcs; 99static struct func_list *graph_funcs;
99 100
101static int func_stack;
102
100struct filter_pids { 103struct filter_pids {
101 struct filter_pids *next; 104 struct filter_pids *next;
102 int pid; 105 int pid;
@@ -560,6 +563,7 @@ static void set_plugin(const char *name)
560{ 563{
561 FILE *fp; 564 FILE *fp;
562 char *path; 565 char *path;
566 char zero = '0';
563 567
564 path = tracecmd_get_tracing_file("current_tracer"); 568 path = tracecmd_get_tracing_file("current_tracer");
565 fp = fopen(path, "w"); 569 fp = fopen(path, "w");
@@ -569,6 +573,16 @@ static void set_plugin(const char *name)
569 573
570 fwrite(name, 1, strlen(name), fp); 574 fwrite(name, 1, strlen(name), fp);
571 fclose(fp); 575 fclose(fp);
576
577 if (strncmp(name, "function", 8) != 0)
578 return;
579
580 /* Make sure func_stack_trace option is disabled */
581 path = tracecmd_get_tracing_file("options/func_stack_trace");
582 fp = fopen(path, "w");
583 tracecmd_put_tracing_file(path);
584 fwrite(&zero, 1, 1, fp);
585 fclose(fp);
572} 586}
573 587
574static void save_option(const char *option) 588static void save_option(const char *option)
@@ -1525,11 +1539,44 @@ static void write_func_file(const char *file, struct func_list **list)
1525 tracecmd_put_tracing_file(path); 1539 tracecmd_put_tracing_file(path);
1526} 1540}
1527 1541
1542static int functions_filtered(void)
1543{
1544 char buf[1] = { '#' };
1545 char *path;
1546 int fd;
1547
1548 path = tracecmd_get_tracing_file("set_ftrace_filter");
1549 fd = open(path, O_RDONLY);
1550 tracecmd_put_tracing_file(path);
1551 if (fd < 0)
1552 return 0;
1553
1554 /*
1555 * If functions are not filtered, than the first character
1556 * will be '#'. Make sure it is not an '#' and also not space.
1557 */
1558 read(fd, buf, 1);
1559 close(fd);
1560
1561 if (buf[0] == '#' || isspace(buf[0]))
1562 return 0;
1563 return 1;
1564}
1565
1528static void set_funcs(void) 1566static void set_funcs(void)
1529{ 1567{
1530 write_func_file("set_ftrace_filter", &filter_funcs); 1568 write_func_file("set_ftrace_filter", &filter_funcs);
1531 write_func_file("set_ftrace_notrace", &notrace_funcs); 1569 write_func_file("set_ftrace_notrace", &notrace_funcs);
1532 write_func_file("set_graph_function", &graph_funcs); 1570 write_func_file("set_graph_function", &graph_funcs);
1571
1572 /* make sure we are filtering functions */
1573 if (func_stack) {
1574 if (!functions_filtered()) {
1575 disable_all();
1576 die("Function stack trace set, but functions not filtered");
1577 }
1578 save_option(FUNC_STACK_TRACE);
1579 }
1533} 1580}
1534 1581
1535static void add_func(struct func_list **list, const char *func) 1582static void add_func(struct func_list **list, const char *func)
@@ -1810,6 +1857,7 @@ static void record_all_events(void)
1810} 1857}
1811 1858
1812enum { 1859enum {
1860 OPT_funcstack = 254,
1813 OPT_date = 255, 1861 OPT_date = 255,
1814}; 1862};
1815 1863
@@ -1867,6 +1915,7 @@ void trace_record (int argc, char **argv)
1867 int option_index = 0; 1915 int option_index = 0;
1868 static struct option long_options[] = { 1916 static struct option long_options[] = {
1869 {"date", no_argument, NULL, OPT_date}, 1917 {"date", no_argument, NULL, OPT_date},
1918 {"func-stack", no_argument, NULL, OPT_funcstack},
1870 {"help", no_argument, NULL, '?'}, 1919 {"help", no_argument, NULL, '?'},
1871 {NULL, 0, NULL, 0} 1920 {NULL, 0, NULL, 0}
1872 }; 1921 };
@@ -1957,7 +2006,8 @@ void trace_record (int argc, char **argv)
1957 case 'p': 2006 case 'p':
1958 if (plugin) 2007 if (plugin)
1959 die("only one plugin allowed"); 2008 die("only one plugin allowed");
1960 plugin = optarg; 2009 for (plugin = optarg; isspace(*plugin); plugin++)
2010 ;
1961 fprintf(stderr, " plugin %s\n", plugin); 2011 fprintf(stderr, " plugin %s\n", plugin);
1962 break; 2012 break;
1963 case 'd': 2013 case 'd':
@@ -2012,11 +2062,18 @@ void trace_record (int argc, char **argv)
2012 case OPT_date: 2062 case OPT_date:
2013 date = 1; 2063 date = 1;
2014 break; 2064 break;
2065 case OPT_funcstack:
2066 func_stack = 1;
2067 break;
2015 default: 2068 default:
2016 usage(argv); 2069 usage(argv);
2017 } 2070 }
2018 } 2071 }
2019 2072
2073 if (strncmp(plugin, "function", 8) == 0 &&
2074 func_stack && !filter_funcs)
2075 die("Must supply function filtering with --func-stack\n");
2076
2020 if (do_ptrace && !filter_task && (filter_pid < 0)) 2077 if (do_ptrace && !filter_task && (filter_pid < 0))
2021 die(" -c can only be used with -F or -P"); 2078 die(" -c can only be used with -F or -P");
2022 2079
diff --git a/trace-usage.c b/trace-usage.c
index 1ecc8fa..4b171fe 100644
--- a/trace-usage.c
+++ b/trace-usage.c
@@ -40,6 +40,8 @@ static struct usage_help usage_help[] = {
40 " -b change kernel buffersize (in kilobytes per CPU)\n" 40 " -b change kernel buffersize (in kilobytes per CPU)\n"
41 " -k do not reset the buffers after tracing.\n" 41 " -k do not reset the buffers after tracing.\n"
42 " -i do not fail if an event is not found\n" 42 " -i do not fail if an event is not found\n"
43 " --func-stack perform a stack trace for function tracer\n"
44 " (use with caution)\n"
43 }, 45 },
44 { 46 {
45 "start", 47 "start",