2 * Copyright (C) 2009, 2010 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
4 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation;
8 * version 2.1 of the License (not later!)
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this program; if not, see <http://www.gnu.org/licenses>
18 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24 #include "event-parse.h"
25 #include "event-utils.h"
26 #include "trace-seq.h"
28 static struct func_stack
{
37 struct tep_plugin_option plugin_options
[] =
41 .plugin_alias
= "ftrace",
43 "Print parent of functions for function events",
47 .plugin_alias
= "ftrace",
49 "Try to show function call indents, based on parents",
57 static struct tep_plugin_option
*ftrace_parent
= &plugin_options
[0];
58 static struct tep_plugin_option
*ftrace_indent
= &plugin_options
[1];
60 static void add_child(struct func_stack
*stack
, const char *child
, int pos
)
67 if (pos
< stack
->size
)
68 free(stack
->stack
[pos
]);
72 ptr
= realloc(stack
->stack
, sizeof(char *) *
73 (stack
->size
+ STK_BLK
));
75 warning("could not allocate plugin memory\n");
81 for (i
= stack
->size
; i
< stack
->size
+ STK_BLK
; i
++)
82 stack
->stack
[i
] = NULL
;
83 stack
->size
+= STK_BLK
;
86 stack
->stack
[pos
] = strdup(child
);
89 static int add_and_get_index(const char *parent
, const char *child
, int cpu
)
97 struct func_stack
*ptr
;
99 ptr
= realloc(fstack
, sizeof(*fstack
) * (cpu
+ 1));
101 warning("could not allocate plugin memory\n");
107 /* Account for holes in the cpu count */
108 for (i
= cpus
+ 1; i
<= cpu
; i
++)
109 memset(&fstack
[i
], 0, sizeof(fstack
[i
]));
113 for (i
= 0; i
< fstack
[cpu
].size
&& fstack
[cpu
].stack
[i
]; i
++) {
114 if (strcmp(parent
, fstack
[cpu
].stack
[i
]) == 0) {
115 add_child(&fstack
[cpu
], child
, i
+1);
121 add_child(&fstack
[cpu
], parent
, 0);
122 add_child(&fstack
[cpu
], child
, 1);
126 static int function_handler(struct trace_seq
*s
, struct tep_record
*record
,
127 struct tep_event
*event
, void *context
)
129 struct tep_handle
*tep
= event
->tep
;
130 unsigned long long function
;
131 unsigned long long pfunction
;
136 if (tep_get_field_val(s
, event
, "ip", record
, &function
, 1))
137 return trace_seq_putc(s
, '!');
139 func
= tep_find_function(tep
, function
);
141 if (tep_get_field_val(s
, event
, "parent_ip", record
, &pfunction
, 1))
142 return trace_seq_putc(s
, '!');
144 parent
= tep_find_function(tep
, pfunction
);
146 if (parent
&& ftrace_indent
->set
)
147 index
= add_and_get_index(parent
, func
, record
->cpu
);
149 trace_seq_printf(s
, "%*s", index
*3, "");
152 trace_seq_printf(s
, "%s", func
);
154 trace_seq_printf(s
, "0x%llx", function
);
156 if (ftrace_parent
->set
) {
157 trace_seq_printf(s
, " <-- ");
159 trace_seq_printf(s
, "%s", parent
);
161 trace_seq_printf(s
, "0x%llx", pfunction
);
167 int TEP_PLUGIN_LOADER(struct tep_handle
*tep
)
169 tep_register_event_handler(tep
, -1, "ftrace", "function",
170 function_handler
, NULL
);
172 tep_plugin_add_options("ftrace", plugin_options
);
177 void TEP_PLUGIN_UNLOADER(struct tep_handle
*tep
)
181 tep_unregister_event_handler(tep
, -1, "ftrace", "function",
182 function_handler
, NULL
);
184 for (i
= 0; i
<= cpus
; i
++) {
185 for (x
= 0; x
< fstack
[i
].size
&& fstack
[i
].stack
[x
]; x
++)
186 free(fstack
[i
].stack
[x
]);
187 free(fstack
[i
].stack
);
190 tep_plugin_remove_options(plugin_options
);