diff options
Diffstat (limited to 'trace-ftrace.c')
-rw-r--r-- | trace-ftrace.c | 88 |
1 files changed, 64 insertions, 24 deletions
diff --git a/trace-ftrace.c b/trace-ftrace.c index f12b221..193e85d 100644 --- a/trace-ftrace.c +++ b/trace-ftrace.c | |||
@@ -25,9 +25,36 @@ | |||
25 | 25 | ||
26 | #include "trace-cmd.h" | 26 | #include "trace-cmd.h" |
27 | 27 | ||
28 | static struct event_format *fgraph_ret_event; | 28 | static void find_long_size(struct tracecmd_ftrace *finfo) |
29 | static int fgraph_ret_id; | 29 | { |
30 | static int long_size; | 30 | finfo->long_size = tracecmd_long_size(finfo->handle); |
31 | } | ||
32 | |||
33 | #define long_size_check(handle) \ | ||
34 | do { \ | ||
35 | if (!finfo->long_size) \ | ||
36 | find_long_size(finfo); \ | ||
37 | } while (0) | ||
38 | |||
39 | static int find_ret_event(struct tracecmd_ftrace *finfo, struct pevent *pevent) | ||
40 | { | ||
41 | struct event_format *event; | ||
42 | |||
43 | /* Store the func ret id and event for later use */ | ||
44 | event = pevent_find_event_by_name(pevent, "ftrace", "funcgraph_exit"); | ||
45 | if (!event) | ||
46 | return -1; | ||
47 | |||
48 | finfo->fgraph_ret_id = event->id; | ||
49 | finfo->fgraph_ret_event = event; | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | #define ret_event_check(finfo, pevent) \ | ||
54 | do { \ | ||
55 | if (!finfo->fgraph_ret_event && find_ret_event(finfo, pevent) < 0) \ | ||
56 | return -1; \ | ||
57 | } while (0) | ||
31 | 58 | ||
32 | static int function_handler(struct trace_seq *s, struct record *record, | 59 | static int function_handler(struct trace_seq *s, struct record *record, |
33 | struct event_format *event, void *context) | 60 | struct event_format *event, void *context) |
@@ -61,27 +88,28 @@ static int function_handler(struct trace_seq *s, struct record *record, | |||
61 | 88 | ||
62 | static struct record * | 89 | static struct record * |
63 | get_return_for_leaf(struct trace_seq *s, int cpu, int cur_pid, | 90 | get_return_for_leaf(struct trace_seq *s, int cpu, int cur_pid, |
64 | unsigned long long cur_func, struct record *next) | 91 | unsigned long long cur_func, struct record *next, |
92 | struct tracecmd_ftrace *finfo) | ||
65 | { | 93 | { |
66 | unsigned long long val; | 94 | unsigned long long val; |
67 | unsigned long long type; | 95 | unsigned long long type; |
68 | unsigned long long pid; | 96 | unsigned long long pid; |
69 | 97 | ||
70 | /* Searching a common field, can use any event */ | 98 | /* Searching a common field, can use any event */ |
71 | if (pevent_get_common_field_val(s, fgraph_ret_event, "common_type", next, &type, 1)) | 99 | if (pevent_get_common_field_val(s, finfo->fgraph_ret_event, "common_type", next, &type, 1)) |
72 | return NULL; | 100 | return NULL; |
73 | 101 | ||
74 | if (type != fgraph_ret_id) | 102 | if (type != finfo->fgraph_ret_id) |
75 | return NULL; | 103 | return NULL; |
76 | 104 | ||
77 | if (pevent_get_common_field_val(s, fgraph_ret_event, "common_pid", next, &pid, 1)) | 105 | if (pevent_get_common_field_val(s, finfo->fgraph_ret_event, "common_pid", next, &pid, 1)) |
78 | return NULL; | 106 | return NULL; |
79 | 107 | ||
80 | if (cur_pid != pid) | 108 | if (cur_pid != pid) |
81 | return NULL; | 109 | return NULL; |
82 | 110 | ||
83 | /* We aleady know this is a funcgraph_ret_event */ | 111 | /* We aleady know this is a funcgraph_ret_event */ |
84 | if (pevent_get_field_val(s, fgraph_ret_event, "func", next, &val, 1)) | 112 | if (pevent_get_field_val(s, finfo->fgraph_ret_event, "func", next, &val, 1)) |
85 | return NULL; | 113 | return NULL; |
86 | 114 | ||
87 | if (cur_func != val) | 115 | if (cur_func != val) |
@@ -146,7 +174,8 @@ static void print_graph_duration(struct trace_seq *s, unsigned long long duratio | |||
146 | static int | 174 | static int |
147 | print_graph_entry_leaf(struct trace_seq *s, | 175 | print_graph_entry_leaf(struct trace_seq *s, |
148 | struct event_format *event, | 176 | struct event_format *event, |
149 | struct record *record, struct record *ret_rec) | 177 | struct record *record, struct record *ret_rec, |
178 | struct tracecmd_ftrace *finfo) | ||
150 | { | 179 | { |
151 | struct pevent *pevent = event->pevent; | 180 | struct pevent *pevent = event->pevent; |
152 | unsigned long long rettime, calltime; | 181 | unsigned long long rettime, calltime; |
@@ -155,11 +184,10 @@ print_graph_entry_leaf(struct trace_seq *s, | |||
155 | const char *func; | 184 | const char *func; |
156 | int i; | 185 | int i; |
157 | 186 | ||
158 | 187 | if (pevent_get_field_val(s, finfo->fgraph_ret_event, "rettime", ret_rec, &rettime, 1)) | |
159 | if (pevent_get_field_val(s, fgraph_ret_event, "rettime", ret_rec, &rettime, 1)) | ||
160 | return trace_seq_putc(s, '!'); | 188 | return trace_seq_putc(s, '!'); |
161 | 189 | ||
162 | if (pevent_get_field_val(s, fgraph_ret_event, "calltime", ret_rec, &calltime, 1)) | 190 | if (pevent_get_field_val(s, finfo->fgraph_ret_event, "calltime", ret_rec, &calltime, 1)) |
163 | return trace_seq_putc(s, '!'); | 191 | return trace_seq_putc(s, '!'); |
164 | 192 | ||
165 | duration = rettime - calltime; | 193 | duration = rettime - calltime; |
@@ -225,10 +253,13 @@ static int | |||
225 | fgraph_ent_handler(struct trace_seq *s, struct record *record, | 253 | fgraph_ent_handler(struct trace_seq *s, struct record *record, |
226 | struct event_format *event, void *context) | 254 | struct event_format *event, void *context) |
227 | { | 255 | { |
256 | struct tracecmd_ftrace *finfo = context; | ||
228 | struct record *rec; | 257 | struct record *rec; |
229 | unsigned long long val, pid; | 258 | unsigned long long val, pid; |
230 | int cpu = record->cpu; | 259 | int cpu = record->cpu; |
231 | 260 | ||
261 | ret_event_check(finfo, event->pevent); | ||
262 | |||
232 | if (pevent_get_common_field_val(s, event, "common_pid", record, &pid, 1)) | 263 | if (pevent_get_common_field_val(s, event, "common_pid", record, &pid, 1)) |
233 | return trace_seq_putc(s, '!'); | 264 | return trace_seq_putc(s, '!'); |
234 | 265 | ||
@@ -237,14 +268,14 @@ fgraph_ent_handler(struct trace_seq *s, struct record *record, | |||
237 | 268 | ||
238 | rec = tracecmd_peek_data(tracecmd_curr_thread_handle, cpu); | 269 | rec = tracecmd_peek_data(tracecmd_curr_thread_handle, cpu); |
239 | if (rec) | 270 | if (rec) |
240 | rec = get_return_for_leaf(s, cpu, pid, val, rec); | 271 | rec = get_return_for_leaf(s, cpu, pid, val, rec, finfo); |
241 | 272 | ||
242 | if (rec) { | 273 | if (rec) { |
243 | /* | 274 | /* |
244 | * If this is a leaf function, then get_return_for_leaf | 275 | * If this is a leaf function, then get_return_for_leaf |
245 | * returns the return of the function | 276 | * returns the return of the function |
246 | */ | 277 | */ |
247 | print_graph_entry_leaf(s, event, record, rec); | 278 | print_graph_entry_leaf(s, event, record, rec, finfo); |
248 | free_record(rec); | 279 | free_record(rec); |
249 | } else | 280 | } else |
250 | print_graph_nested(s, event, record); | 281 | print_graph_nested(s, event, record); |
@@ -256,10 +287,13 @@ static int | |||
256 | fgraph_ret_handler(struct trace_seq *s, struct record *record, | 287 | fgraph_ret_handler(struct trace_seq *s, struct record *record, |
257 | struct event_format *event, void *context) | 288 | struct event_format *event, void *context) |
258 | { | 289 | { |
290 | struct tracecmd_ftrace *finfo = context; | ||
259 | unsigned long long rettime, calltime; | 291 | unsigned long long rettime, calltime; |
260 | unsigned long long duration, depth; | 292 | unsigned long long duration, depth; |
261 | int i; | 293 | int i; |
262 | 294 | ||
295 | ret_event_check(finfo, event->pevent); | ||
296 | |||
263 | if (pevent_get_field_val(s, event, "rettime", record, &rettime, 1)) | 297 | if (pevent_get_field_val(s, event, "rettime", record, &rettime, 1)) |
264 | return trace_seq_putc(s, '!'); | 298 | return trace_seq_putc(s, '!'); |
265 | 299 | ||
@@ -290,6 +324,7 @@ static int | |||
290 | trace_stack_handler(struct trace_seq *s, struct record *record, | 324 | trace_stack_handler(struct trace_seq *s, struct record *record, |
291 | struct event_format *event, void *context) | 325 | struct event_format *event, void *context) |
292 | { | 326 | { |
327 | struct tracecmd_ftrace *finfo = context; | ||
293 | struct format_field *field; | 328 | struct format_field *field; |
294 | unsigned long long addr; | 329 | unsigned long long addr; |
295 | const char *func; | 330 | const char *func; |
@@ -304,11 +339,13 @@ trace_stack_handler(struct trace_seq *s, struct record *record, | |||
304 | 339 | ||
305 | trace_seq_puts(s, "<stack trace>\n"); | 340 | trace_seq_puts(s, "<stack trace>\n"); |
306 | 341 | ||
307 | for (i = 0; i < field->size; i += long_size) { | 342 | long_size_check(finfo); |
343 | |||
344 | for (i = 0; i < field->size; i += finfo->long_size) { | ||
308 | addr = pevent_read_number(event->pevent, | 345 | addr = pevent_read_number(event->pevent, |
309 | data + field->offset + i, long_size); | 346 | data + field->offset + i, finfo->long_size); |
310 | 347 | ||
311 | if ((long_size == 8 && addr == (unsigned long long)-1) || | 348 | if ((finfo->long_size == 8 && addr == (unsigned long long)-1) || |
312 | ((int)addr == -1)) | 349 | ((int)addr == -1)) |
313 | break; | 350 | break; |
314 | 351 | ||
@@ -322,34 +359,37 @@ trace_stack_handler(struct trace_seq *s, struct record *record, | |||
322 | return 0; | 359 | return 0; |
323 | } | 360 | } |
324 | 361 | ||
325 | int tracecmd_ftrace_overrides(struct tracecmd_input *handle) | 362 | int tracecmd_ftrace_overrides(struct tracecmd_input *handle, |
363 | struct tracecmd_ftrace *finfo) | ||
326 | { | 364 | { |
327 | struct pevent *pevent; | 365 | struct pevent *pevent; |
328 | struct event_format *event; | 366 | struct event_format *event; |
329 | 367 | ||
368 | finfo->handle = handle; | ||
369 | |||
330 | pevent = tracecmd_get_pevent(handle); | 370 | pevent = tracecmd_get_pevent(handle); |
331 | 371 | ||
332 | pevent_register_event_handler(pevent, -1, "ftrace", "function", | 372 | pevent_register_event_handler(pevent, -1, "ftrace", "function", |
333 | function_handler, NULL); | 373 | function_handler, NULL); |
334 | 374 | ||
335 | pevent_register_event_handler(pevent, -1, "ftrace", "funcgraph_entry", | 375 | pevent_register_event_handler(pevent, -1, "ftrace", "funcgraph_entry", |
336 | fgraph_ent_handler, NULL); | 376 | fgraph_ent_handler, finfo); |
337 | 377 | ||
338 | pevent_register_event_handler(pevent, -1, "ftrace", "funcgraph_exit", | 378 | pevent_register_event_handler(pevent, -1, "ftrace", "funcgraph_exit", |
339 | fgraph_ret_handler, NULL); | 379 | fgraph_ret_handler, finfo); |
340 | 380 | ||
341 | pevent_register_event_handler(pevent, -1, "ftrace", "kernel_stack", | 381 | pevent_register_event_handler(pevent, -1, "ftrace", "kernel_stack", |
342 | trace_stack_handler, NULL); | 382 | trace_stack_handler, finfo); |
343 | 383 | ||
344 | /* Store the func ret id and event for later use */ | 384 | /* Store the func ret id and event for later use */ |
345 | event = pevent_find_event_by_name(pevent, "ftrace", "funcgraph_exit"); | 385 | event = pevent_find_event_by_name(pevent, "ftrace", "funcgraph_exit"); |
346 | if (!event) | 386 | if (!event) |
347 | return 0; | 387 | return 0; |
348 | 388 | ||
349 | long_size = tracecmd_long_size(handle); | 389 | finfo->long_size = tracecmd_long_size(handle); |
350 | 390 | ||
351 | fgraph_ret_id = event->id; | 391 | finfo->fgraph_ret_id = event->id; |
352 | fgraph_ret_event = event; | 392 | finfo->fgraph_ret_event = event; |
353 | 393 | ||
354 | return 0; | 394 | return 0; |
355 | } | 395 | } |