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"
27 static struct func_stack
{
36 struct pevent_plugin_option plugin_options
[] =
40 .plugin_alias
= "ftrace",
42 "Print parent of functions for function events",
46 .plugin_alias
= "ftrace",
48 "Try to show function call indents, based on parents",
56 static struct pevent_plugin_option
*ftrace_parent
= &plugin_options
[0];
57 static struct pevent_plugin_option
*ftrace_indent
= &plugin_options
[1];
59 static void add_child(struct func_stack
*stack
, const char *child
, int pos
)
66 if (pos
< stack
->size
)
67 free(stack
->stack
[pos
]);
71 ptr
= realloc(stack
->stack
, sizeof(char *) *
72 (stack
->size
+ STK_BLK
));
74 warning("could not allocate plugin memory\n");
80 for (i
= stack
->size
; i
< stack
->size
+ STK_BLK
; i
++)
81 stack
->stack
[i
] = NULL
;
82 stack
->size
+= STK_BLK
;
85 stack
->stack
[pos
] = strdup(child
);
88 static int add_and_get_index(const char *parent
, const char *child
, int cpu
)
96 struct func_stack
*ptr
;
98 ptr
= realloc(fstack
, sizeof(*fstack
) * (cpu
+ 1));
100 warning("could not allocate plugin memory\n");
106 /* Account for holes in the cpu count */
107 for (i
= cpus
+ 1; i
<= cpu
; i
++)
108 memset(&fstack
[i
], 0, sizeof(fstack
[i
]));
112 for (i
= 0; i
< fstack
[cpu
].size
&& fstack
[cpu
].stack
[i
]; i
++) {
113 if (strcmp(parent
, fstack
[cpu
].stack
[i
]) == 0) {
114 add_child(&fstack
[cpu
], child
, i
+1);
120 add_child(&fstack
[cpu
], parent
, 0);
121 add_child(&fstack
[cpu
], child
, 1);
125 static int function_handler(struct trace_seq
*s
, struct pevent_record
*record
,
126 struct event_format
*event
, void *context
)
128 struct pevent
*pevent
= event
->pevent
;
129 unsigned long long function
;
130 unsigned long long pfunction
;
135 if (pevent_get_field_val(s
, event
, "ip", record
, &function
, 1))
136 return trace_seq_putc(s
, '!');
138 func
= pevent_find_function(pevent
, function
);
140 if (pevent_get_field_val(s
, event
, "parent_ip", record
, &pfunction
, 1))
141 return trace_seq_putc(s
, '!');
143 parent
= pevent_find_function(pevent
, pfunction
);
145 if (parent
&& ftrace_indent
->set
)
146 index
= add_and_get_index(parent
, func
, record
->cpu
);
148 trace_seq_printf(s
, "%*s", index
*3, "");
151 trace_seq_printf(s
, "%s", func
);
153 trace_seq_printf(s
, "0x%llx", function
);
155 if (ftrace_parent
->set
) {
156 trace_seq_printf(s
, " <-- ");
158 trace_seq_printf(s
, "%s", parent
);
160 trace_seq_printf(s
, "0x%llx", pfunction
);
166 int PEVENT_PLUGIN_LOADER(struct pevent
*pevent
)
168 pevent_register_event_handler(pevent
, -1, "ftrace", "function",
169 function_handler
, NULL
);
171 traceevent_plugin_add_options("ftrace", plugin_options
);
176 void PEVENT_PLUGIN_UNLOADER(struct pevent
*pevent
)
180 pevent_unregister_event_handler(pevent
, -1, "ftrace", "function",
181 function_handler
, NULL
);
183 for (i
= 0; i
<= cpus
; i
++) {
184 for (x
= 0; x
< fstack
[i
].size
&& fstack
[i
].stack
[x
]; x
++)
185 free(fstack
[i
].stack
[x
]);
186 free(fstack
[i
].stack
);
189 traceevent_plugin_remove_options(plugin_options
);