diff options
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 126 |
1 files changed, 123 insertions, 3 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 6f233698518e..02c708ae0d42 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -15,15 +15,19 @@ | |||
15 | #include "trace.h" | 15 | #include "trace.h" |
16 | #include "trace_output.h" | 16 | #include "trace_output.h" |
17 | 17 | ||
18 | /* When set, irq functions will be ignored */ | ||
19 | static int ftrace_graph_skip_irqs; | ||
20 | |||
18 | struct fgraph_cpu_data { | 21 | struct fgraph_cpu_data { |
19 | pid_t last_pid; | 22 | pid_t last_pid; |
20 | int depth; | 23 | int depth; |
24 | int depth_irq; | ||
21 | int ignore; | 25 | int ignore; |
22 | unsigned long enter_funcs[FTRACE_RETFUNC_DEPTH]; | 26 | unsigned long enter_funcs[FTRACE_RETFUNC_DEPTH]; |
23 | }; | 27 | }; |
24 | 28 | ||
25 | struct fgraph_data { | 29 | struct fgraph_data { |
26 | struct fgraph_cpu_data *cpu_data; | 30 | struct fgraph_cpu_data __percpu *cpu_data; |
27 | 31 | ||
28 | /* Place to preserve last processed entry. */ | 32 | /* Place to preserve last processed entry. */ |
29 | struct ftrace_graph_ent_entry ent; | 33 | struct ftrace_graph_ent_entry ent; |
@@ -41,6 +45,7 @@ struct fgraph_data { | |||
41 | #define TRACE_GRAPH_PRINT_PROC 0x8 | 45 | #define TRACE_GRAPH_PRINT_PROC 0x8 |
42 | #define TRACE_GRAPH_PRINT_DURATION 0x10 | 46 | #define TRACE_GRAPH_PRINT_DURATION 0x10 |
43 | #define TRACE_GRAPH_PRINT_ABS_TIME 0x20 | 47 | #define TRACE_GRAPH_PRINT_ABS_TIME 0x20 |
48 | #define TRACE_GRAPH_PRINT_IRQS 0x40 | ||
44 | 49 | ||
45 | static struct tracer_opt trace_opts[] = { | 50 | static struct tracer_opt trace_opts[] = { |
46 | /* Display overruns? (for self-debug purpose) */ | 51 | /* Display overruns? (for self-debug purpose) */ |
@@ -55,13 +60,15 @@ static struct tracer_opt trace_opts[] = { | |||
55 | { TRACER_OPT(funcgraph-duration, TRACE_GRAPH_PRINT_DURATION) }, | 60 | { TRACER_OPT(funcgraph-duration, TRACE_GRAPH_PRINT_DURATION) }, |
56 | /* Display absolute time of an entry */ | 61 | /* Display absolute time of an entry */ |
57 | { TRACER_OPT(funcgraph-abstime, TRACE_GRAPH_PRINT_ABS_TIME) }, | 62 | { TRACER_OPT(funcgraph-abstime, TRACE_GRAPH_PRINT_ABS_TIME) }, |
63 | /* Display interrupts */ | ||
64 | { TRACER_OPT(funcgraph-irqs, TRACE_GRAPH_PRINT_IRQS) }, | ||
58 | { } /* Empty entry */ | 65 | { } /* Empty entry */ |
59 | }; | 66 | }; |
60 | 67 | ||
61 | static struct tracer_flags tracer_flags = { | 68 | static struct tracer_flags tracer_flags = { |
62 | /* Don't display overruns and proc by default */ | 69 | /* Don't display overruns and proc by default */ |
63 | .val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD | | 70 | .val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD | |
64 | TRACE_GRAPH_PRINT_DURATION, | 71 | TRACE_GRAPH_PRINT_DURATION | TRACE_GRAPH_PRINT_IRQS, |
65 | .opts = trace_opts | 72 | .opts = trace_opts |
66 | }; | 73 | }; |
67 | 74 | ||
@@ -204,6 +211,14 @@ int __trace_graph_entry(struct trace_array *tr, | |||
204 | return 1; | 211 | return 1; |
205 | } | 212 | } |
206 | 213 | ||
214 | static inline int ftrace_graph_ignore_irqs(void) | ||
215 | { | ||
216 | if (!ftrace_graph_skip_irqs) | ||
217 | return 0; | ||
218 | |||
219 | return in_irq(); | ||
220 | } | ||
221 | |||
207 | int trace_graph_entry(struct ftrace_graph_ent *trace) | 222 | int trace_graph_entry(struct ftrace_graph_ent *trace) |
208 | { | 223 | { |
209 | struct trace_array *tr = graph_array; | 224 | struct trace_array *tr = graph_array; |
@@ -218,7 +233,8 @@ int trace_graph_entry(struct ftrace_graph_ent *trace) | |||
218 | return 0; | 233 | return 0; |
219 | 234 | ||
220 | /* trace it when it is-nested-in or is a function enabled. */ | 235 | /* trace it when it is-nested-in or is a function enabled. */ |
221 | if (!(trace->depth || ftrace_graph_addr(trace->func))) | 236 | if (!(trace->depth || ftrace_graph_addr(trace->func)) || |
237 | ftrace_graph_ignore_irqs()) | ||
222 | return 0; | 238 | return 0; |
223 | 239 | ||
224 | local_irq_save(flags); | 240 | local_irq_save(flags); |
@@ -855,6 +871,92 @@ print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s, | |||
855 | return 0; | 871 | return 0; |
856 | } | 872 | } |
857 | 873 | ||
874 | /* | ||
875 | * Entry check for irq code | ||
876 | * | ||
877 | * returns 1 if | ||
878 | * - we are inside irq code | ||
879 | * - we just extered irq code | ||
880 | * | ||
881 | * retunns 0 if | ||
882 | * - funcgraph-interrupts option is set | ||
883 | * - we are not inside irq code | ||
884 | */ | ||
885 | static int | ||
886 | check_irq_entry(struct trace_iterator *iter, u32 flags, | ||
887 | unsigned long addr, int depth) | ||
888 | { | ||
889 | int cpu = iter->cpu; | ||
890 | struct fgraph_data *data = iter->private; | ||
891 | int *depth_irq = &(per_cpu_ptr(data->cpu_data, cpu)->depth_irq); | ||
892 | |||
893 | if (flags & TRACE_GRAPH_PRINT_IRQS) | ||
894 | return 0; | ||
895 | |||
896 | /* | ||
897 | * We are inside the irq code | ||
898 | */ | ||
899 | if (*depth_irq >= 0) | ||
900 | return 1; | ||
901 | |||
902 | if ((addr < (unsigned long)__irqentry_text_start) || | ||
903 | (addr >= (unsigned long)__irqentry_text_end)) | ||
904 | return 0; | ||
905 | |||
906 | /* | ||
907 | * We are entering irq code. | ||
908 | */ | ||
909 | *depth_irq = depth; | ||
910 | return 1; | ||
911 | } | ||
912 | |||
913 | /* | ||
914 | * Return check for irq code | ||
915 | * | ||
916 | * returns 1 if | ||
917 | * - we are inside irq code | ||
918 | * - we just left irq code | ||
919 | * | ||
920 | * returns 0 if | ||
921 | * - funcgraph-interrupts option is set | ||
922 | * - we are not inside irq code | ||
923 | */ | ||
924 | static int | ||
925 | check_irq_return(struct trace_iterator *iter, u32 flags, int depth) | ||
926 | { | ||
927 | int cpu = iter->cpu; | ||
928 | struct fgraph_data *data = iter->private; | ||
929 | int *depth_irq = &(per_cpu_ptr(data->cpu_data, cpu)->depth_irq); | ||
930 | |||
931 | if (flags & TRACE_GRAPH_PRINT_IRQS) | ||
932 | return 0; | ||
933 | |||
934 | /* | ||
935 | * We are not inside the irq code. | ||
936 | */ | ||
937 | if (*depth_irq == -1) | ||
938 | return 0; | ||
939 | |||
940 | /* | ||
941 | * We are inside the irq code, and this is returning entry. | ||
942 | * Let's not trace it and clear the entry depth, since | ||
943 | * we are out of irq code. | ||
944 | * | ||
945 | * This condition ensures that we 'leave the irq code' once | ||
946 | * we are out of the entry depth. Thus protecting us from | ||
947 | * the RETURN entry loss. | ||
948 | */ | ||
949 | if (*depth_irq >= depth) { | ||
950 | *depth_irq = -1; | ||
951 | return 1; | ||
952 | } | ||
953 | |||
954 | /* | ||
955 | * We are inside the irq code, and this is not the entry. | ||
956 | */ | ||
957 | return 1; | ||
958 | } | ||
959 | |||
858 | static enum print_line_t | 960 | static enum print_line_t |
859 | print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s, | 961 | print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s, |
860 | struct trace_iterator *iter, u32 flags) | 962 | struct trace_iterator *iter, u32 flags) |
@@ -865,6 +967,9 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s, | |||
865 | static enum print_line_t ret; | 967 | static enum print_line_t ret; |
866 | int cpu = iter->cpu; | 968 | int cpu = iter->cpu; |
867 | 969 | ||
970 | if (check_irq_entry(iter, flags, call->func, call->depth)) | ||
971 | return TRACE_TYPE_HANDLED; | ||
972 | |||
868 | if (print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func, flags)) | 973 | if (print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func, flags)) |
869 | return TRACE_TYPE_PARTIAL_LINE; | 974 | return TRACE_TYPE_PARTIAL_LINE; |
870 | 975 | ||
@@ -902,6 +1007,9 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, | |||
902 | int ret; | 1007 | int ret; |
903 | int i; | 1008 | int i; |
904 | 1009 | ||
1010 | if (check_irq_return(iter, flags, trace->depth)) | ||
1011 | return TRACE_TYPE_HANDLED; | ||
1012 | |||
905 | if (data) { | 1013 | if (data) { |
906 | struct fgraph_cpu_data *cpu_data; | 1014 | struct fgraph_cpu_data *cpu_data; |
907 | int cpu = iter->cpu; | 1015 | int cpu = iter->cpu; |
@@ -1210,9 +1318,12 @@ void graph_trace_open(struct trace_iterator *iter) | |||
1210 | pid_t *pid = &(per_cpu_ptr(data->cpu_data, cpu)->last_pid); | 1318 | pid_t *pid = &(per_cpu_ptr(data->cpu_data, cpu)->last_pid); |
1211 | int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth); | 1319 | int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth); |
1212 | int *ignore = &(per_cpu_ptr(data->cpu_data, cpu)->ignore); | 1320 | int *ignore = &(per_cpu_ptr(data->cpu_data, cpu)->ignore); |
1321 | int *depth_irq = &(per_cpu_ptr(data->cpu_data, cpu)->depth_irq); | ||
1322 | |||
1213 | *pid = -1; | 1323 | *pid = -1; |
1214 | *depth = 0; | 1324 | *depth = 0; |
1215 | *ignore = 0; | 1325 | *ignore = 0; |
1326 | *depth_irq = -1; | ||
1216 | } | 1327 | } |
1217 | 1328 | ||
1218 | iter->private = data; | 1329 | iter->private = data; |
@@ -1235,6 +1346,14 @@ void graph_trace_close(struct trace_iterator *iter) | |||
1235 | } | 1346 | } |
1236 | } | 1347 | } |
1237 | 1348 | ||
1349 | static int func_graph_set_flag(u32 old_flags, u32 bit, int set) | ||
1350 | { | ||
1351 | if (bit == TRACE_GRAPH_PRINT_IRQS) | ||
1352 | ftrace_graph_skip_irqs = !set; | ||
1353 | |||
1354 | return 0; | ||
1355 | } | ||
1356 | |||
1238 | static struct trace_event_functions graph_functions = { | 1357 | static struct trace_event_functions graph_functions = { |
1239 | .trace = print_graph_function_event, | 1358 | .trace = print_graph_function_event, |
1240 | }; | 1359 | }; |
@@ -1261,6 +1380,7 @@ static struct tracer graph_trace __read_mostly = { | |||
1261 | .print_line = print_graph_function, | 1380 | .print_line = print_graph_function, |
1262 | .print_header = print_graph_headers, | 1381 | .print_header = print_graph_headers, |
1263 | .flags = &tracer_flags, | 1382 | .flags = &tracer_flags, |
1383 | .set_flag = func_graph_set_flag, | ||
1264 | #ifdef CONFIG_FTRACE_SELFTEST | 1384 | #ifdef CONFIG_FTRACE_SELFTEST |
1265 | .selftest = trace_selftest_startup_function_graph, | 1385 | .selftest = trace_selftest_startup_function_graph, |
1266 | #endif | 1386 | #endif |