diff options
author | Jamie Gennis | 2012-11-21 22:14:09 -0600 |
---|---|---|
committer | Jamie Gennis | 2013-03-12 18:33:54 -0500 |
commit | 0e6c2090296eb82fd3a61276ff79137c6a488e66 (patch) | |
tree | 10e23b6c97d16773b577b48949923bb89e6a88c0 | |
parent | 4e9ef397ec3cfb04b64f165d40dcf1b501415718 (diff) | |
download | kernel-common-android-3.4.tar.gz kernel-common-android-3.4.tar.xz kernel-common-android-3.4.zip |
trace: add non-hierarchical function_graph optionandroid-3.4
Add the 'funcgraph-flat' option to the function_graph tracer to use the default
trace printing format rather than the hierarchical formatting normally used.
Change-Id: If2900bfb86e6f8f51379f56da4f6fabafa630909
Signed-off-by: Jamie Gennis <jgennis@google.com>
-rw-r--r-- | Documentation/trace/ftrace.txt | 29 | ||||
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 43 | ||||
-rw-r--r-- | kernel/trace/trace_output.c | 164 |
3 files changed, 205 insertions, 31 deletions
diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt index 6f51fed45f2..a5c45d7b0b9 100644 --- a/Documentation/trace/ftrace.txt +++ b/Documentation/trace/ftrace.txt | |||
@@ -1458,6 +1458,35 @@ will produce: | |||
1458 | 1) 1.449 us | } | 1458 | 1) 1.449 us | } |
1459 | 1459 | ||
1460 | 1460 | ||
1461 | You can disable the hierarchical function call formatting and instead print a | ||
1462 | flat list of function entry and return events. This uses the format described | ||
1463 | in the Output Formatting section and respects all the trace options that | ||
1464 | control that formatting. Hierarchical formatting is the default. | ||
1465 | |||
1466 | hierachical: echo nofuncgraph-flat > trace_options | ||
1467 | flat: echo funcgraph-flat > trace_options | ||
1468 | |||
1469 | ie: | ||
1470 | |||
1471 | # tracer: function_graph | ||
1472 | # | ||
1473 | # entries-in-buffer/entries-written: 68355/68355 #P:2 | ||
1474 | # | ||
1475 | # _-----=> irqs-off | ||
1476 | # / _----=> need-resched | ||
1477 | # | / _---=> hardirq/softirq | ||
1478 | # || / _--=> preempt-depth | ||
1479 | # ||| / delay | ||
1480 | # TASK-PID CPU# |||| TIMESTAMP FUNCTION | ||
1481 | # | | | |||| | | | ||
1482 | sh-1806 [001] d... 198.843443: graph_ent: func=_raw_spin_lock | ||
1483 | sh-1806 [001] d... 198.843445: graph_ent: func=__raw_spin_lock | ||
1484 | sh-1806 [001] d..1 198.843447: graph_ret: func=__raw_spin_lock | ||
1485 | sh-1806 [001] d..1 198.843449: graph_ret: func=_raw_spin_lock | ||
1486 | sh-1806 [001] d..1 198.843451: graph_ent: func=_raw_spin_unlock_irqrestore | ||
1487 | sh-1806 [001] d... 198.843453: graph_ret: func=_raw_spin_unlock_irqrestore | ||
1488 | |||
1489 | |||
1461 | You might find other useful features for this tracer in the | 1490 | You might find other useful features for this tracer in the |
1462 | following "dynamic ftrace" section such as tracing only specific | 1491 | following "dynamic ftrace" section such as tracing only specific |
1463 | functions or tasks. | 1492 | functions or tasks. |
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index a7d2a4c653d..f7f1f37a4c5 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -46,6 +46,8 @@ struct fgraph_data { | |||
46 | #define TRACE_GRAPH_PRINT_DURATION 0x10 | 46 | #define TRACE_GRAPH_PRINT_DURATION 0x10 |
47 | #define TRACE_GRAPH_PRINT_ABS_TIME 0x20 | 47 | #define TRACE_GRAPH_PRINT_ABS_TIME 0x20 |
48 | #define TRACE_GRAPH_PRINT_IRQS 0x40 | 48 | #define TRACE_GRAPH_PRINT_IRQS 0x40 |
49 | #define TRACE_GRAPH_PRINT_FLAT 0x80 | ||
50 | |||
49 | 51 | ||
50 | static struct tracer_opt trace_opts[] = { | 52 | static struct tracer_opt trace_opts[] = { |
51 | /* Display overruns? (for self-debug purpose) */ | 53 | /* Display overruns? (for self-debug purpose) */ |
@@ -62,6 +64,8 @@ static struct tracer_opt trace_opts[] = { | |||
62 | { TRACER_OPT(funcgraph-abstime, TRACE_GRAPH_PRINT_ABS_TIME) }, | 64 | { TRACER_OPT(funcgraph-abstime, TRACE_GRAPH_PRINT_ABS_TIME) }, |
63 | /* Display interrupts */ | 65 | /* Display interrupts */ |
64 | { TRACER_OPT(funcgraph-irqs, TRACE_GRAPH_PRINT_IRQS) }, | 66 | { TRACER_OPT(funcgraph-irqs, TRACE_GRAPH_PRINT_IRQS) }, |
67 | /* Use standard trace formatting rather than hierarchical */ | ||
68 | { TRACER_OPT(funcgraph-flat, TRACE_GRAPH_PRINT_FLAT) }, | ||
65 | { } /* Empty entry */ | 69 | { } /* Empty entry */ |
66 | }; | 70 | }; |
67 | 71 | ||
@@ -1222,6 +1226,9 @@ print_graph_function_flags(struct trace_iterator *iter, u32 flags) | |||
1222 | int cpu = iter->cpu; | 1226 | int cpu = iter->cpu; |
1223 | int ret; | 1227 | int ret; |
1224 | 1228 | ||
1229 | if (flags & TRACE_GRAPH_PRINT_FLAT) | ||
1230 | return TRACE_TYPE_UNHANDLED; | ||
1231 | |||
1225 | if (data && per_cpu_ptr(data->cpu_data, cpu)->ignore) { | 1232 | if (data && per_cpu_ptr(data->cpu_data, cpu)->ignore) { |
1226 | per_cpu_ptr(data->cpu_data, cpu)->ignore = 0; | 1233 | per_cpu_ptr(data->cpu_data, cpu)->ignore = 0; |
1227 | return TRACE_TYPE_HANDLED; | 1234 | return TRACE_TYPE_HANDLED; |
@@ -1279,13 +1286,6 @@ print_graph_function(struct trace_iterator *iter) | |||
1279 | return print_graph_function_flags(iter, tracer_flags.val); | 1286 | return print_graph_function_flags(iter, tracer_flags.val); |
1280 | } | 1287 | } |
1281 | 1288 | ||
1282 | static enum print_line_t | ||
1283 | print_graph_function_event(struct trace_iterator *iter, int flags, | ||
1284 | struct trace_event *event) | ||
1285 | { | ||
1286 | return print_graph_function(iter); | ||
1287 | } | ||
1288 | |||
1289 | static void print_lat_header(struct seq_file *s, u32 flags) | 1289 | static void print_lat_header(struct seq_file *s, u32 flags) |
1290 | { | 1290 | { |
1291 | static const char spaces[] = " " /* 16 spaces */ | 1291 | static const char spaces[] = " " /* 16 spaces */ |
@@ -1352,6 +1352,11 @@ void print_graph_headers_flags(struct seq_file *s, u32 flags) | |||
1352 | { | 1352 | { |
1353 | struct trace_iterator *iter = s->private; | 1353 | struct trace_iterator *iter = s->private; |
1354 | 1354 | ||
1355 | if (flags & TRACE_GRAPH_PRINT_FLAT) { | ||
1356 | trace_default_header(s); | ||
1357 | return; | ||
1358 | } | ||
1359 | |||
1355 | if (!(trace_flags & TRACE_ITER_CONTEXT_INFO)) | 1360 | if (!(trace_flags & TRACE_ITER_CONTEXT_INFO)) |
1356 | return; | 1361 | return; |
1357 | 1362 | ||
@@ -1422,20 +1427,6 @@ static int func_graph_set_flag(u32 old_flags, u32 bit, int set) | |||
1422 | return 0; | 1427 | return 0; |
1423 | } | 1428 | } |
1424 | 1429 | ||
1425 | static struct trace_event_functions graph_functions = { | ||
1426 | .trace = print_graph_function_event, | ||
1427 | }; | ||
1428 | |||
1429 | static struct trace_event graph_trace_entry_event = { | ||
1430 | .type = TRACE_GRAPH_ENT, | ||
1431 | .funcs = &graph_functions, | ||
1432 | }; | ||
1433 | |||
1434 | static struct trace_event graph_trace_ret_event = { | ||
1435 | .type = TRACE_GRAPH_RET, | ||
1436 | .funcs = &graph_functions | ||
1437 | }; | ||
1438 | |||
1439 | static struct tracer graph_trace __read_mostly = { | 1430 | static struct tracer graph_trace __read_mostly = { |
1440 | .name = "function_graph", | 1431 | .name = "function_graph", |
1441 | .open = graph_trace_open, | 1432 | .open = graph_trace_open, |
@@ -1458,16 +1449,6 @@ static __init int init_graph_trace(void) | |||
1458 | { | 1449 | { |
1459 | max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1); | 1450 | max_bytes_for_cpu = snprintf(NULL, 0, "%d", nr_cpu_ids - 1); |
1460 | 1451 | ||
1461 | if (!register_ftrace_event(&graph_trace_entry_event)) { | ||
1462 | pr_warning("Warning: could not register graph trace events\n"); | ||
1463 | return 1; | ||
1464 | } | ||
1465 | |||
1466 | if (!register_ftrace_event(&graph_trace_ret_event)) { | ||
1467 | pr_warning("Warning: could not register graph trace events\n"); | ||
1468 | return 1; | ||
1469 | } | ||
1470 | |||
1471 | return register_tracer(&graph_trace); | 1452 | return register_tracer(&graph_trace); |
1472 | } | 1453 | } |
1473 | 1454 | ||
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c index 76377eca50b..cb29ce200e7 100644 --- a/kernel/trace/trace_output.c +++ b/kernel/trace/trace_output.c | |||
@@ -980,6 +980,168 @@ static struct trace_event trace_fn_event = { | |||
980 | .funcs = &trace_fn_funcs, | 980 | .funcs = &trace_fn_funcs, |
981 | }; | 981 | }; |
982 | 982 | ||
983 | /* TRACE_GRAPH_ENT */ | ||
984 | static enum print_line_t trace_graph_ent_trace(struct trace_iterator *iter, int flags, | ||
985 | struct trace_event *event) | ||
986 | { | ||
987 | struct trace_seq *s = &iter->seq; | ||
988 | struct ftrace_graph_ent_entry *field; | ||
989 | |||
990 | trace_assign_type(field, iter->ent); | ||
991 | |||
992 | if (!trace_seq_puts(s, "graph_ent: func=")) | ||
993 | return TRACE_TYPE_PARTIAL_LINE; | ||
994 | |||
995 | if (!seq_print_ip_sym(s, field->graph_ent.func, flags)) | ||
996 | return TRACE_TYPE_PARTIAL_LINE; | ||
997 | |||
998 | if (!trace_seq_puts(s, "\n")) | ||
999 | return TRACE_TYPE_PARTIAL_LINE; | ||
1000 | |||
1001 | return TRACE_TYPE_HANDLED; | ||
1002 | } | ||
1003 | |||
1004 | static enum print_line_t trace_graph_ent_raw(struct trace_iterator *iter, int flags, | ||
1005 | struct trace_event *event) | ||
1006 | { | ||
1007 | struct ftrace_graph_ent_entry *field; | ||
1008 | |||
1009 | trace_assign_type(field, iter->ent); | ||
1010 | |||
1011 | if (!trace_seq_printf(&iter->seq, "%lx %d\n", | ||
1012 | field->graph_ent.func, | ||
1013 | field->graph_ent.depth)) | ||
1014 | return TRACE_TYPE_PARTIAL_LINE; | ||
1015 | |||
1016 | return TRACE_TYPE_HANDLED; | ||
1017 | } | ||
1018 | |||
1019 | static enum print_line_t trace_graph_ent_hex(struct trace_iterator *iter, int flags, | ||
1020 | struct trace_event *event) | ||
1021 | { | ||
1022 | struct ftrace_graph_ent_entry *field; | ||
1023 | struct trace_seq *s = &iter->seq; | ||
1024 | |||
1025 | trace_assign_type(field, iter->ent); | ||
1026 | |||
1027 | SEQ_PUT_HEX_FIELD_RET(s, field->graph_ent.func); | ||
1028 | SEQ_PUT_HEX_FIELD_RET(s, field->graph_ent.depth); | ||
1029 | |||
1030 | return TRACE_TYPE_HANDLED; | ||
1031 | } | ||
1032 | |||
1033 | static enum print_line_t trace_graph_ent_bin(struct trace_iterator *iter, int flags, | ||
1034 | struct trace_event *event) | ||
1035 | { | ||
1036 | struct ftrace_graph_ent_entry *field; | ||
1037 | struct trace_seq *s = &iter->seq; | ||
1038 | |||
1039 | trace_assign_type(field, iter->ent); | ||
1040 | |||
1041 | SEQ_PUT_FIELD_RET(s, field->graph_ent.func); | ||
1042 | SEQ_PUT_FIELD_RET(s, field->graph_ent.depth); | ||
1043 | |||
1044 | return TRACE_TYPE_HANDLED; | ||
1045 | } | ||
1046 | |||
1047 | static struct trace_event_functions trace_graph_ent_funcs = { | ||
1048 | .trace = trace_graph_ent_trace, | ||
1049 | .raw = trace_graph_ent_raw, | ||
1050 | .hex = trace_graph_ent_hex, | ||
1051 | .binary = trace_graph_ent_bin, | ||
1052 | }; | ||
1053 | |||
1054 | static struct trace_event trace_graph_ent_event = { | ||
1055 | .type = TRACE_GRAPH_ENT, | ||
1056 | .funcs = &trace_graph_ent_funcs, | ||
1057 | }; | ||
1058 | |||
1059 | /* TRACE_GRAPH_RET */ | ||
1060 | static enum print_line_t trace_graph_ret_trace(struct trace_iterator *iter, int flags, | ||
1061 | struct trace_event *event) | ||
1062 | { | ||
1063 | struct trace_seq *s = &iter->seq; | ||
1064 | struct trace_entry *entry = iter->ent; | ||
1065 | struct ftrace_graph_ret_entry *field; | ||
1066 | |||
1067 | trace_assign_type(field, entry); | ||
1068 | |||
1069 | if (!trace_seq_puts(s, "graph_ret: func=")) | ||
1070 | return TRACE_TYPE_PARTIAL_LINE; | ||
1071 | |||
1072 | if (!seq_print_ip_sym(s, field->ret.func, flags)) | ||
1073 | return TRACE_TYPE_PARTIAL_LINE; | ||
1074 | |||
1075 | if (!trace_seq_puts(s, "\n")) | ||
1076 | return TRACE_TYPE_PARTIAL_LINE; | ||
1077 | |||
1078 | return TRACE_TYPE_HANDLED; | ||
1079 | } | ||
1080 | |||
1081 | static enum print_line_t trace_graph_ret_raw(struct trace_iterator *iter, int flags, | ||
1082 | struct trace_event *event) | ||
1083 | { | ||
1084 | struct ftrace_graph_ret_entry *field; | ||
1085 | |||
1086 | trace_assign_type(field, iter->ent); | ||
1087 | |||
1088 | if (!trace_seq_printf(&iter->seq, "%lx %lld %lld %ld %d\n", | ||
1089 | field->ret.func, | ||
1090 | field->ret.calltime, | ||
1091 | field->ret.rettime, | ||
1092 | field->ret.overrun, | ||
1093 | field->ret.depth)); | ||
1094 | return TRACE_TYPE_PARTIAL_LINE; | ||
1095 | |||
1096 | return TRACE_TYPE_HANDLED; | ||
1097 | } | ||
1098 | |||
1099 | static enum print_line_t trace_graph_ret_hex(struct trace_iterator *iter, int flags, | ||
1100 | struct trace_event *event) | ||
1101 | { | ||
1102 | struct ftrace_graph_ret_entry *field; | ||
1103 | struct trace_seq *s = &iter->seq; | ||
1104 | |||
1105 | trace_assign_type(field, iter->ent); | ||
1106 | |||
1107 | SEQ_PUT_HEX_FIELD_RET(s, field->ret.func); | ||
1108 | SEQ_PUT_HEX_FIELD_RET(s, field->ret.calltime); | ||
1109 | SEQ_PUT_HEX_FIELD_RET(s, field->ret.rettime); | ||
1110 | SEQ_PUT_HEX_FIELD_RET(s, field->ret.overrun); | ||
1111 | SEQ_PUT_HEX_FIELD_RET(s, field->ret.depth); | ||
1112 | |||
1113 | return TRACE_TYPE_HANDLED; | ||
1114 | } | ||
1115 | |||
1116 | static enum print_line_t trace_graph_ret_bin(struct trace_iterator *iter, int flags, | ||
1117 | struct trace_event *event) | ||
1118 | { | ||
1119 | struct ftrace_graph_ret_entry *field; | ||
1120 | struct trace_seq *s = &iter->seq; | ||
1121 | |||
1122 | trace_assign_type(field, iter->ent); | ||
1123 | |||
1124 | SEQ_PUT_FIELD_RET(s, field->ret.func); | ||
1125 | SEQ_PUT_FIELD_RET(s, field->ret.calltime); | ||
1126 | SEQ_PUT_FIELD_RET(s, field->ret.rettime); | ||
1127 | SEQ_PUT_FIELD_RET(s, field->ret.overrun); | ||
1128 | SEQ_PUT_FIELD_RET(s, field->ret.depth); | ||
1129 | |||
1130 | return TRACE_TYPE_HANDLED; | ||
1131 | } | ||
1132 | |||
1133 | static struct trace_event_functions trace_graph_ret_funcs = { | ||
1134 | .trace = trace_graph_ret_trace, | ||
1135 | .raw = trace_graph_ret_raw, | ||
1136 | .hex = trace_graph_ret_hex, | ||
1137 | .binary = trace_graph_ret_bin, | ||
1138 | }; | ||
1139 | |||
1140 | static struct trace_event trace_graph_ret_event = { | ||
1141 | .type = TRACE_GRAPH_RET, | ||
1142 | .funcs = &trace_graph_ret_funcs, | ||
1143 | }; | ||
1144 | |||
983 | /* TRACE_CTX an TRACE_WAKE */ | 1145 | /* TRACE_CTX an TRACE_WAKE */ |
984 | static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter, | 1146 | static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter, |
985 | char *delim) | 1147 | char *delim) |
@@ -1312,6 +1474,8 @@ static struct trace_event trace_print_event = { | |||
1312 | 1474 | ||
1313 | static struct trace_event *events[] __initdata = { | 1475 | static struct trace_event *events[] __initdata = { |
1314 | &trace_fn_event, | 1476 | &trace_fn_event, |
1477 | &trace_graph_ent_event, | ||
1478 | &trace_graph_ret_event, | ||
1315 | &trace_ctx_event, | 1479 | &trace_ctx_event, |
1316 | &trace_wake_event, | 1480 | &trace_wake_event, |
1317 | &trace_stack_event, | 1481 | &trace_stack_event, |