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 | } |
