aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJamie Gennis2012-11-21 22:14:09 -0600
committerJamie Gennis2013-03-12 18:33:54 -0500
commit0e6c2090296eb82fd3a61276ff79137c6a488e66 (patch)
tree10e23b6c97d16773b577b48949923bb89e6a88c0
parent4e9ef397ec3cfb04b64f165d40dcf1b501415718 (diff)
downloadkernel-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.txt29
-rw-r--r--kernel/trace/trace_functions_graph.c43
-rw-r--r--kernel/trace/trace_output.c164
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
1461You can disable the hierarchical function call formatting and instead print a
1462flat list of function entry and return events. This uses the format described
1463in the Output Formatting section and respects all the trace options that
1464control 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
1461You might find other useful features for this tracer in the 1490You might find other useful features for this tracer in the
1462following "dynamic ftrace" section such as tracing only specific 1491following "dynamic ftrace" section such as tracing only specific
1463functions or tasks. 1492functions 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
50static struct tracer_opt trace_opts[] = { 52static 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
1282static enum print_line_t
1283print_graph_function_event(struct trace_iterator *iter, int flags,
1284 struct trace_event *event)
1285{
1286 return print_graph_function(iter);
1287}
1288
1289static void print_lat_header(struct seq_file *s, u32 flags) 1289static 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
1425static struct trace_event_functions graph_functions = {
1426 .trace = print_graph_function_event,
1427};
1428
1429static struct trace_event graph_trace_entry_event = {
1430 .type = TRACE_GRAPH_ENT,
1431 .funcs = &graph_functions,
1432};
1433
1434static struct trace_event graph_trace_ret_event = {
1435 .type = TRACE_GRAPH_RET,
1436 .funcs = &graph_functions
1437};
1438
1439static struct tracer graph_trace __read_mostly = { 1430static 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 */
984static 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
1004static 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
1019static 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
1033static 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
1047static 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
1054static struct trace_event trace_graph_ent_event = {
1055 .type = TRACE_GRAPH_ENT,
1056 .funcs = &trace_graph_ent_funcs,
1057};
1058
1059/* TRACE_GRAPH_RET */
1060static 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
1081static 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
1099static 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
1116static 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
1133static 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
1140static 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 */
984static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter, 1146static 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
1313static struct trace_event *events[] __initdata = { 1475static 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,