diff options
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 225 |
1 files changed, 110 insertions, 115 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 962cdb24ed81..a7d2a4c653d8 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -74,6 +74,20 @@ static struct tracer_flags tracer_flags = { | |||
74 | 74 | ||
75 | static struct trace_array *graph_array; | 75 | static struct trace_array *graph_array; |
76 | 76 | ||
77 | /* | ||
78 | * DURATION column is being also used to display IRQ signs, | ||
79 | * following values are used by print_graph_irq and others | ||
80 | * to fill in space into DURATION column. | ||
81 | */ | ||
82 | enum { | ||
83 | DURATION_FILL_FULL = -1, | ||
84 | DURATION_FILL_START = -2, | ||
85 | DURATION_FILL_END = -3, | ||
86 | }; | ||
87 | |||
88 | static enum print_line_t | ||
89 | print_graph_duration(unsigned long long duration, struct trace_seq *s, | ||
90 | u32 flags); | ||
77 | 91 | ||
78 | /* Add a function return address to the trace stack on thread info.*/ | 92 | /* Add a function return address to the trace stack on thread info.*/ |
79 | int | 93 | int |
@@ -213,7 +227,7 @@ int __trace_graph_entry(struct trace_array *tr, | |||
213 | 227 | ||
214 | static inline int ftrace_graph_ignore_irqs(void) | 228 | static inline int ftrace_graph_ignore_irqs(void) |
215 | { | 229 | { |
216 | if (!ftrace_graph_skip_irqs) | 230 | if (!ftrace_graph_skip_irqs || trace_recursion_test(TRACE_IRQ_BIT)) |
217 | return 0; | 231 | return 0; |
218 | 232 | ||
219 | return in_irq(); | 233 | return in_irq(); |
@@ -577,32 +591,6 @@ get_return_for_leaf(struct trace_iterator *iter, | |||
577 | return next; | 591 | return next; |
578 | } | 592 | } |
579 | 593 | ||
580 | /* Signal a overhead of time execution to the output */ | ||
581 | static int | ||
582 | print_graph_overhead(unsigned long long duration, struct trace_seq *s, | ||
583 | u32 flags) | ||
584 | { | ||
585 | /* If duration disappear, we don't need anything */ | ||
586 | if (!(flags & TRACE_GRAPH_PRINT_DURATION)) | ||
587 | return 1; | ||
588 | |||
589 | /* Non nested entry or return */ | ||
590 | if (duration == -1) | ||
591 | return trace_seq_printf(s, " "); | ||
592 | |||
593 | if (flags & TRACE_GRAPH_PRINT_OVERHEAD) { | ||
594 | /* Duration exceeded 100 msecs */ | ||
595 | if (duration > 100000ULL) | ||
596 | return trace_seq_printf(s, "! "); | ||
597 | |||
598 | /* Duration exceeded 10 msecs */ | ||
599 | if (duration > 10000ULL) | ||
600 | return trace_seq_printf(s, "+ "); | ||
601 | } | ||
602 | |||
603 | return trace_seq_printf(s, " "); | ||
604 | } | ||
605 | |||
606 | static int print_graph_abs_time(u64 t, struct trace_seq *s) | 594 | static int print_graph_abs_time(u64 t, struct trace_seq *s) |
607 | { | 595 | { |
608 | unsigned long usecs_rem; | 596 | unsigned long usecs_rem; |
@@ -625,34 +613,36 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr, | |||
625 | addr >= (unsigned long)__irqentry_text_end) | 613 | addr >= (unsigned long)__irqentry_text_end) |
626 | return TRACE_TYPE_UNHANDLED; | 614 | return TRACE_TYPE_UNHANDLED; |
627 | 615 | ||
628 | /* Absolute time */ | 616 | if (trace_flags & TRACE_ITER_CONTEXT_INFO) { |
629 | if (flags & TRACE_GRAPH_PRINT_ABS_TIME) { | 617 | /* Absolute time */ |
630 | ret = print_graph_abs_time(iter->ts, s); | 618 | if (flags & TRACE_GRAPH_PRINT_ABS_TIME) { |
631 | if (!ret) | 619 | ret = print_graph_abs_time(iter->ts, s); |
632 | return TRACE_TYPE_PARTIAL_LINE; | 620 | if (!ret) |
633 | } | 621 | return TRACE_TYPE_PARTIAL_LINE; |
622 | } | ||
634 | 623 | ||
635 | /* Cpu */ | 624 | /* Cpu */ |
636 | if (flags & TRACE_GRAPH_PRINT_CPU) { | 625 | if (flags & TRACE_GRAPH_PRINT_CPU) { |
637 | ret = print_graph_cpu(s, cpu); | 626 | ret = print_graph_cpu(s, cpu); |
638 | if (ret == TRACE_TYPE_PARTIAL_LINE) | 627 | if (ret == TRACE_TYPE_PARTIAL_LINE) |
639 | return TRACE_TYPE_PARTIAL_LINE; | 628 | return TRACE_TYPE_PARTIAL_LINE; |
640 | } | 629 | } |
641 | 630 | ||
642 | /* Proc */ | 631 | /* Proc */ |
643 | if (flags & TRACE_GRAPH_PRINT_PROC) { | 632 | if (flags & TRACE_GRAPH_PRINT_PROC) { |
644 | ret = print_graph_proc(s, pid); | 633 | ret = print_graph_proc(s, pid); |
645 | if (ret == TRACE_TYPE_PARTIAL_LINE) | 634 | if (ret == TRACE_TYPE_PARTIAL_LINE) |
646 | return TRACE_TYPE_PARTIAL_LINE; | 635 | return TRACE_TYPE_PARTIAL_LINE; |
647 | ret = trace_seq_printf(s, " | "); | 636 | ret = trace_seq_printf(s, " | "); |
648 | if (!ret) | 637 | if (!ret) |
649 | return TRACE_TYPE_PARTIAL_LINE; | 638 | return TRACE_TYPE_PARTIAL_LINE; |
639 | } | ||
650 | } | 640 | } |
651 | 641 | ||
652 | /* No overhead */ | 642 | /* No overhead */ |
653 | ret = print_graph_overhead(-1, s, flags); | 643 | ret = print_graph_duration(DURATION_FILL_START, s, flags); |
654 | if (!ret) | 644 | if (ret != TRACE_TYPE_HANDLED) |
655 | return TRACE_TYPE_PARTIAL_LINE; | 645 | return ret; |
656 | 646 | ||
657 | if (type == TRACE_GRAPH_ENT) | 647 | if (type == TRACE_GRAPH_ENT) |
658 | ret = trace_seq_printf(s, "==========>"); | 648 | ret = trace_seq_printf(s, "==========>"); |
@@ -662,9 +652,10 @@ print_graph_irq(struct trace_iterator *iter, unsigned long addr, | |||
662 | if (!ret) | 652 | if (!ret) |
663 | return TRACE_TYPE_PARTIAL_LINE; | 653 | return TRACE_TYPE_PARTIAL_LINE; |
664 | 654 | ||
665 | /* Don't close the duration column if haven't one */ | 655 | ret = print_graph_duration(DURATION_FILL_END, s, flags); |
666 | if (flags & TRACE_GRAPH_PRINT_DURATION) | 656 | if (ret != TRACE_TYPE_HANDLED) |
667 | trace_seq_printf(s, " |"); | 657 | return ret; |
658 | |||
668 | ret = trace_seq_printf(s, "\n"); | 659 | ret = trace_seq_printf(s, "\n"); |
669 | 660 | ||
670 | if (!ret) | 661 | if (!ret) |
@@ -716,9 +707,49 @@ trace_print_graph_duration(unsigned long long duration, struct trace_seq *s) | |||
716 | } | 707 | } |
717 | 708 | ||
718 | static enum print_line_t | 709 | static enum print_line_t |
719 | print_graph_duration(unsigned long long duration, struct trace_seq *s) | 710 | print_graph_duration(unsigned long long duration, struct trace_seq *s, |
711 | u32 flags) | ||
720 | { | 712 | { |
721 | int ret; | 713 | int ret = -1; |
714 | |||
715 | if (!(flags & TRACE_GRAPH_PRINT_DURATION) || | ||
716 | !(trace_flags & TRACE_ITER_CONTEXT_INFO)) | ||
717 | return TRACE_TYPE_HANDLED; | ||
718 | |||
719 | /* No real adata, just filling the column with spaces */ | ||
720 | switch (duration) { | ||
721 | case DURATION_FILL_FULL: | ||
722 | ret = trace_seq_printf(s, " | "); | ||
723 | return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE; | ||
724 | case DURATION_FILL_START: | ||
725 | ret = trace_seq_printf(s, " "); | ||
726 | return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE; | ||
727 | case DURATION_FILL_END: | ||
728 | ret = trace_seq_printf(s, " |"); | ||
729 | return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE; | ||
730 | } | ||
731 | |||
732 | /* Signal a overhead of time execution to the output */ | ||
733 | if (flags & TRACE_GRAPH_PRINT_OVERHEAD) { | ||
734 | /* Duration exceeded 100 msecs */ | ||
735 | if (duration > 100000ULL) | ||
736 | ret = trace_seq_printf(s, "! "); | ||
737 | /* Duration exceeded 10 msecs */ | ||
738 | else if (duration > 10000ULL) | ||
739 | ret = trace_seq_printf(s, "+ "); | ||
740 | } | ||
741 | |||
742 | /* | ||
743 | * The -1 means we either did not exceed the duration tresholds | ||
744 | * or we dont want to print out the overhead. Either way we need | ||
745 | * to fill out the space. | ||
746 | */ | ||
747 | if (ret == -1) | ||
748 | ret = trace_seq_printf(s, " "); | ||
749 | |||
750 | /* Catching here any failure happenned above */ | ||
751 | if (!ret) | ||
752 | return TRACE_TYPE_PARTIAL_LINE; | ||
722 | 753 | ||
723 | ret = trace_print_graph_duration(duration, s); | 754 | ret = trace_print_graph_duration(duration, s); |
724 | if (ret != TRACE_TYPE_HANDLED) | 755 | if (ret != TRACE_TYPE_HANDLED) |
@@ -767,18 +798,11 @@ print_graph_entry_leaf(struct trace_iterator *iter, | |||
767 | cpu_data->enter_funcs[call->depth] = 0; | 798 | cpu_data->enter_funcs[call->depth] = 0; |
768 | } | 799 | } |
769 | 800 | ||
770 | /* Overhead */ | 801 | /* Overhead and duration */ |
771 | ret = print_graph_overhead(duration, s, flags); | 802 | ret = print_graph_duration(duration, s, flags); |
772 | if (!ret) | 803 | if (ret == TRACE_TYPE_PARTIAL_LINE) |
773 | return TRACE_TYPE_PARTIAL_LINE; | 804 | return TRACE_TYPE_PARTIAL_LINE; |
774 | 805 | ||
775 | /* Duration */ | ||
776 | if (flags & TRACE_GRAPH_PRINT_DURATION) { | ||
777 | ret = print_graph_duration(duration, s); | ||
778 | if (ret == TRACE_TYPE_PARTIAL_LINE) | ||
779 | return TRACE_TYPE_PARTIAL_LINE; | ||
780 | } | ||
781 | |||
782 | /* Function */ | 806 | /* Function */ |
783 | for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) { | 807 | for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) { |
784 | ret = trace_seq_printf(s, " "); | 808 | ret = trace_seq_printf(s, " "); |
@@ -815,17 +839,10 @@ print_graph_entry_nested(struct trace_iterator *iter, | |||
815 | cpu_data->enter_funcs[call->depth] = call->func; | 839 | cpu_data->enter_funcs[call->depth] = call->func; |
816 | } | 840 | } |
817 | 841 | ||
818 | /* No overhead */ | ||
819 | ret = print_graph_overhead(-1, s, flags); | ||
820 | if (!ret) | ||
821 | return TRACE_TYPE_PARTIAL_LINE; | ||
822 | |||
823 | /* No time */ | 842 | /* No time */ |
824 | if (flags & TRACE_GRAPH_PRINT_DURATION) { | 843 | ret = print_graph_duration(DURATION_FILL_FULL, s, flags); |
825 | ret = trace_seq_printf(s, " | "); | 844 | if (ret != TRACE_TYPE_HANDLED) |
826 | if (!ret) | 845 | return ret; |
827 | return TRACE_TYPE_PARTIAL_LINE; | ||
828 | } | ||
829 | 846 | ||
830 | /* Function */ | 847 | /* Function */ |
831 | for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) { | 848 | for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) { |
@@ -865,6 +882,9 @@ print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s, | |||
865 | return TRACE_TYPE_PARTIAL_LINE; | 882 | return TRACE_TYPE_PARTIAL_LINE; |
866 | } | 883 | } |
867 | 884 | ||
885 | if (!(trace_flags & TRACE_ITER_CONTEXT_INFO)) | ||
886 | return 0; | ||
887 | |||
868 | /* Absolute time */ | 888 | /* Absolute time */ |
869 | if (flags & TRACE_GRAPH_PRINT_ABS_TIME) { | 889 | if (flags & TRACE_GRAPH_PRINT_ABS_TIME) { |
870 | ret = print_graph_abs_time(iter->ts, s); | 890 | ret = print_graph_abs_time(iter->ts, s); |
@@ -1078,18 +1098,11 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, | |||
1078 | if (print_graph_prologue(iter, s, 0, 0, flags)) | 1098 | if (print_graph_prologue(iter, s, 0, 0, flags)) |
1079 | return TRACE_TYPE_PARTIAL_LINE; | 1099 | return TRACE_TYPE_PARTIAL_LINE; |
1080 | 1100 | ||
1081 | /* Overhead */ | 1101 | /* Overhead and duration */ |
1082 | ret = print_graph_overhead(duration, s, flags); | 1102 | ret = print_graph_duration(duration, s, flags); |
1083 | if (!ret) | 1103 | if (ret == TRACE_TYPE_PARTIAL_LINE) |
1084 | return TRACE_TYPE_PARTIAL_LINE; | 1104 | return TRACE_TYPE_PARTIAL_LINE; |
1085 | 1105 | ||
1086 | /* Duration */ | ||
1087 | if (flags & TRACE_GRAPH_PRINT_DURATION) { | ||
1088 | ret = print_graph_duration(duration, s); | ||
1089 | if (ret == TRACE_TYPE_PARTIAL_LINE) | ||
1090 | return TRACE_TYPE_PARTIAL_LINE; | ||
1091 | } | ||
1092 | |||
1093 | /* Closing brace */ | 1106 | /* Closing brace */ |
1094 | for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++) { | 1107 | for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++) { |
1095 | ret = trace_seq_printf(s, " "); | 1108 | ret = trace_seq_printf(s, " "); |
@@ -1146,17 +1159,10 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent, | |||
1146 | if (print_graph_prologue(iter, s, 0, 0, flags)) | 1159 | if (print_graph_prologue(iter, s, 0, 0, flags)) |
1147 | return TRACE_TYPE_PARTIAL_LINE; | 1160 | return TRACE_TYPE_PARTIAL_LINE; |
1148 | 1161 | ||
1149 | /* No overhead */ | ||
1150 | ret = print_graph_overhead(-1, s, flags); | ||
1151 | if (!ret) | ||
1152 | return TRACE_TYPE_PARTIAL_LINE; | ||
1153 | |||
1154 | /* No time */ | 1162 | /* No time */ |
1155 | if (flags & TRACE_GRAPH_PRINT_DURATION) { | 1163 | ret = print_graph_duration(DURATION_FILL_FULL, s, flags); |
1156 | ret = trace_seq_printf(s, " | "); | 1164 | if (ret != TRACE_TYPE_HANDLED) |
1157 | if (!ret) | 1165 | return ret; |
1158 | return TRACE_TYPE_PARTIAL_LINE; | ||
1159 | } | ||
1160 | 1166 | ||
1161 | /* Indentation */ | 1167 | /* Indentation */ |
1162 | if (depth > 0) | 1168 | if (depth > 0) |
@@ -1207,7 +1213,7 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent, | |||
1207 | 1213 | ||
1208 | 1214 | ||
1209 | enum print_line_t | 1215 | enum print_line_t |
1210 | __print_graph_function_flags(struct trace_iterator *iter, u32 flags) | 1216 | print_graph_function_flags(struct trace_iterator *iter, u32 flags) |
1211 | { | 1217 | { |
1212 | struct ftrace_graph_ent_entry *field; | 1218 | struct ftrace_graph_ent_entry *field; |
1213 | struct fgraph_data *data = iter->private; | 1219 | struct fgraph_data *data = iter->private; |
@@ -1270,18 +1276,7 @@ __print_graph_function_flags(struct trace_iterator *iter, u32 flags) | |||
1270 | static enum print_line_t | 1276 | static enum print_line_t |
1271 | print_graph_function(struct trace_iterator *iter) | 1277 | print_graph_function(struct trace_iterator *iter) |
1272 | { | 1278 | { |
1273 | return __print_graph_function_flags(iter, tracer_flags.val); | 1279 | return print_graph_function_flags(iter, tracer_flags.val); |
1274 | } | ||
1275 | |||
1276 | enum print_line_t print_graph_function_flags(struct trace_iterator *iter, | ||
1277 | u32 flags) | ||
1278 | { | ||
1279 | if (trace_flags & TRACE_ITER_LATENCY_FMT) | ||
1280 | flags |= TRACE_GRAPH_PRINT_DURATION; | ||
1281 | else | ||
1282 | flags |= TRACE_GRAPH_PRINT_ABS_TIME; | ||
1283 | |||
1284 | return __print_graph_function_flags(iter, flags); | ||
1285 | } | 1280 | } |
1286 | 1281 | ||
1287 | static enum print_line_t | 1282 | static enum print_line_t |
@@ -1309,8 +1304,7 @@ static void print_lat_header(struct seq_file *s, u32 flags) | |||
1309 | seq_printf(s, "#%.*s / _----=> need-resched \n", size, spaces); | 1304 | seq_printf(s, "#%.*s / _----=> need-resched \n", size, spaces); |
1310 | seq_printf(s, "#%.*s| / _---=> hardirq/softirq \n", size, spaces); | 1305 | seq_printf(s, "#%.*s| / _---=> hardirq/softirq \n", size, spaces); |
1311 | seq_printf(s, "#%.*s|| / _--=> preempt-depth \n", size, spaces); | 1306 | seq_printf(s, "#%.*s|| / _--=> preempt-depth \n", size, spaces); |
1312 | seq_printf(s, "#%.*s||| / _-=> lock-depth \n", size, spaces); | 1307 | seq_printf(s, "#%.*s||| / \n", size, spaces); |
1313 | seq_printf(s, "#%.*s|||| / \n", size, spaces); | ||
1314 | } | 1308 | } |
1315 | 1309 | ||
1316 | static void __print_graph_headers_flags(struct seq_file *s, u32 flags) | 1310 | static void __print_graph_headers_flags(struct seq_file *s, u32 flags) |
@@ -1329,7 +1323,7 @@ static void __print_graph_headers_flags(struct seq_file *s, u32 flags) | |||
1329 | if (flags & TRACE_GRAPH_PRINT_PROC) | 1323 | if (flags & TRACE_GRAPH_PRINT_PROC) |
1330 | seq_printf(s, " TASK/PID "); | 1324 | seq_printf(s, " TASK/PID "); |
1331 | if (lat) | 1325 | if (lat) |
1332 | seq_printf(s, "|||||"); | 1326 | seq_printf(s, "||||"); |
1333 | if (flags & TRACE_GRAPH_PRINT_DURATION) | 1327 | if (flags & TRACE_GRAPH_PRINT_DURATION) |
1334 | seq_printf(s, " DURATION "); | 1328 | seq_printf(s, " DURATION "); |
1335 | seq_printf(s, " FUNCTION CALLS\n"); | 1329 | seq_printf(s, " FUNCTION CALLS\n"); |
@@ -1343,7 +1337,7 @@ static void __print_graph_headers_flags(struct seq_file *s, u32 flags) | |||
1343 | if (flags & TRACE_GRAPH_PRINT_PROC) | 1337 | if (flags & TRACE_GRAPH_PRINT_PROC) |
1344 | seq_printf(s, " | | "); | 1338 | seq_printf(s, " | | "); |
1345 | if (lat) | 1339 | if (lat) |
1346 | seq_printf(s, "|||||"); | 1340 | seq_printf(s, "||||"); |
1347 | if (flags & TRACE_GRAPH_PRINT_DURATION) | 1341 | if (flags & TRACE_GRAPH_PRINT_DURATION) |
1348 | seq_printf(s, " | | "); | 1342 | seq_printf(s, " | | "); |
1349 | seq_printf(s, " | | | |\n"); | 1343 | seq_printf(s, " | | | |\n"); |
@@ -1358,15 +1352,16 @@ void print_graph_headers_flags(struct seq_file *s, u32 flags) | |||
1358 | { | 1352 | { |
1359 | struct trace_iterator *iter = s->private; | 1353 | struct trace_iterator *iter = s->private; |
1360 | 1354 | ||
1355 | if (!(trace_flags & TRACE_ITER_CONTEXT_INFO)) | ||
1356 | return; | ||
1357 | |||
1361 | if (trace_flags & TRACE_ITER_LATENCY_FMT) { | 1358 | if (trace_flags & TRACE_ITER_LATENCY_FMT) { |
1362 | /* print nothing if the buffers are empty */ | 1359 | /* print nothing if the buffers are empty */ |
1363 | if (trace_empty(iter)) | 1360 | if (trace_empty(iter)) |
1364 | return; | 1361 | return; |
1365 | 1362 | ||
1366 | print_trace_header(s, iter); | 1363 | print_trace_header(s, iter); |
1367 | flags |= TRACE_GRAPH_PRINT_DURATION; | 1364 | } |
1368 | } else | ||
1369 | flags |= TRACE_GRAPH_PRINT_ABS_TIME; | ||
1370 | 1365 | ||
1371 | __print_graph_headers_flags(s, flags); | 1366 | __print_graph_headers_flags(s, flags); |
1372 | } | 1367 | } |