diff options
| -rw-r--r-- | kernel/trace/trace_functions_graph.c | 52 |
1 files changed, 43 insertions, 9 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 112561df2a0a..e998a824e9db 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
| @@ -18,6 +18,7 @@ struct fgraph_cpu_data { | |||
| 18 | pid_t last_pid; | 18 | pid_t last_pid; |
| 19 | int depth; | 19 | int depth; |
| 20 | int ignore; | 20 | int ignore; |
| 21 | unsigned long enter_funcs[FTRACE_RETFUNC_DEPTH]; | ||
| 21 | }; | 22 | }; |
| 22 | 23 | ||
| 23 | struct fgraph_data { | 24 | struct fgraph_data { |
| @@ -670,15 +671,21 @@ print_graph_entry_leaf(struct trace_iterator *iter, | |||
| 670 | duration = graph_ret->rettime - graph_ret->calltime; | 671 | duration = graph_ret->rettime - graph_ret->calltime; |
| 671 | 672 | ||
| 672 | if (data) { | 673 | if (data) { |
| 674 | struct fgraph_cpu_data *cpu_data; | ||
| 673 | int cpu = iter->cpu; | 675 | int cpu = iter->cpu; |
| 674 | int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth); | 676 | |
| 677 | cpu_data = per_cpu_ptr(data->cpu_data, cpu); | ||
| 675 | 678 | ||
| 676 | /* | 679 | /* |
| 677 | * Comments display at + 1 to depth. Since | 680 | * Comments display at + 1 to depth. Since |
| 678 | * this is a leaf function, keep the comments | 681 | * this is a leaf function, keep the comments |
| 679 | * equal to this depth. | 682 | * equal to this depth. |
| 680 | */ | 683 | */ |
| 681 | *depth = call->depth - 1; | 684 | cpu_data->depth = call->depth - 1; |
| 685 | |||
| 686 | /* No need to keep this function around for this depth */ | ||
| 687 | if (call->depth < FTRACE_RETFUNC_DEPTH) | ||
| 688 | cpu_data->enter_funcs[call->depth] = 0; | ||
| 682 | } | 689 | } |
| 683 | 690 | ||
| 684 | /* Overhead */ | 691 | /* Overhead */ |
| @@ -718,10 +725,15 @@ print_graph_entry_nested(struct trace_iterator *iter, | |||
| 718 | int i; | 725 | int i; |
| 719 | 726 | ||
| 720 | if (data) { | 727 | if (data) { |
| 728 | struct fgraph_cpu_data *cpu_data; | ||
| 721 | int cpu = iter->cpu; | 729 | int cpu = iter->cpu; |
| 722 | int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth); | ||
| 723 | 730 | ||
| 724 | *depth = call->depth; | 731 | cpu_data = per_cpu_ptr(data->cpu_data, cpu); |
| 732 | cpu_data->depth = call->depth; | ||
| 733 | |||
| 734 | /* Save this function pointer to see if the exit matches */ | ||
| 735 | if (call->depth < FTRACE_RETFUNC_DEPTH) | ||
| 736 | cpu_data->enter_funcs[call->depth] = call->func; | ||
| 725 | } | 737 | } |
| 726 | 738 | ||
| 727 | /* No overhead */ | 739 | /* No overhead */ |
| @@ -851,18 +863,28 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, | |||
| 851 | struct fgraph_data *data = iter->private; | 863 | struct fgraph_data *data = iter->private; |
| 852 | pid_t pid = ent->pid; | 864 | pid_t pid = ent->pid; |
| 853 | int cpu = iter->cpu; | 865 | int cpu = iter->cpu; |
| 866 | int func_match = 1; | ||
| 854 | int ret; | 867 | int ret; |
| 855 | int i; | 868 | int i; |
| 856 | 869 | ||
| 857 | if (data) { | 870 | if (data) { |
| 858 | int *depth = &(per_cpu_ptr(data->cpu_data, cpu)->depth); | 871 | struct fgraph_cpu_data *cpu_data; |
| 872 | int cpu = iter->cpu; | ||
| 873 | |||
| 874 | cpu_data = per_cpu_ptr(data->cpu_data, cpu); | ||
| 859 | 875 | ||
| 860 | /* | 876 | /* |
| 861 | * Comments display at + 1 to depth. This is the | 877 | * Comments display at + 1 to depth. This is the |
| 862 | * return from a function, we now want the comments | 878 | * return from a function, we now want the comments |
| 863 | * to display at the same level of the bracket. | 879 | * to display at the same level of the bracket. |
| 864 | */ | 880 | */ |
| 865 | *depth = trace->depth - 1; | 881 | cpu_data->depth = trace->depth - 1; |
| 882 | |||
| 883 | if (trace->depth < FTRACE_RETFUNC_DEPTH) { | ||
| 884 | if (cpu_data->enter_funcs[trace->depth] != trace->func) | ||
| 885 | func_match = 0; | ||
| 886 | cpu_data->enter_funcs[trace->depth] = 0; | ||
| 887 | } | ||
| 866 | } | 888 | } |
| 867 | 889 | ||
| 868 | if (print_graph_prologue(iter, s, 0, 0)) | 890 | if (print_graph_prologue(iter, s, 0, 0)) |
| @@ -887,9 +909,21 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, | |||
| 887 | return TRACE_TYPE_PARTIAL_LINE; | 909 | return TRACE_TYPE_PARTIAL_LINE; |
| 888 | } | 910 | } |
| 889 | 911 | ||
| 890 | ret = trace_seq_printf(s, "}\n"); | 912 | /* |
| 891 | if (!ret) | 913 | * If the return function does not have a matching entry, |
| 892 | return TRACE_TYPE_PARTIAL_LINE; | 914 | * then the entry was lost. Instead of just printing |
| 915 | * the '}' and letting the user guess what function this | ||
| 916 | * belongs to, write out the function name. | ||
| 917 | */ | ||
| 918 | if (func_match) { | ||
| 919 | ret = trace_seq_printf(s, "}\n"); | ||
| 920 | if (!ret) | ||
| 921 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 922 | } else { | ||
| 923 | ret = trace_seq_printf(s, "} (%ps)\n", (void *)trace->func); | ||
| 924 | if (!ret) | ||
| 925 | return TRACE_TYPE_PARTIAL_LINE; | ||
| 926 | } | ||
| 893 | 927 | ||
| 894 | /* Overrun */ | 928 | /* Overrun */ |
| 895 | if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERRUN) { | 929 | if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERRUN) { |
