diff options
author | Steven Rostedt <srostedt@redhat.com> | 2011-03-11 16:52:40 -0500 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2011-03-11 16:52:40 -0500 |
commit | df843687135e7ffca2d6b70ca5453698e4067bf0 (patch) | |
tree | 584312fc355d46a9176d7a7c803ef884e508936f | |
parent | 46a183d56259978644643643bea126972333a476 (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.txt | 7 | ||||
-rw-r--r-- | trace-record.c | 59 | ||||
-rw-r--r-- | trace-usage.c | 2 |
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; | |||
97 | static struct func_list *notrace_funcs; | 98 | static struct func_list *notrace_funcs; |
98 | static struct func_list *graph_funcs; | 99 | static struct func_list *graph_funcs; |
99 | 100 | ||
101 | static int func_stack; | ||
102 | |||
100 | struct filter_pids { | 103 | struct 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 | ||
574 | static void save_option(const char *option) | 588 | static 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 | ||
1542 | static 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 | |||
1528 | static void set_funcs(void) | 1566 | static 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", ¬race_funcs); | 1569 | write_func_file("set_ftrace_notrace", ¬race_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 | ||
1535 | static void add_func(struct func_list **list, const char *func) | 1582 | static void add_func(struct func_list **list, const char *func) |
@@ -1810,6 +1857,7 @@ static void record_all_events(void) | |||
1810 | } | 1857 | } |
1811 | 1858 | ||
1812 | enum { | 1859 | enum { |
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", |