diff options
author | Frederic Weisbecker <fweisbec@gmail.com> | 2009-02-06 12:30:44 -0500 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2009-02-09 06:37:27 -0500 |
commit | b91facc367366b3f71375f337eb5997ec9ab4e69 (patch) | |
tree | 1f7c8914f493080cadcfdec23b33d9a5936fe98b /kernel/trace/trace_functions_graph.c | |
parent | 1dfba05d0f1a9b4245bb242a7c17fe448811a520 (diff) |
tracing/function-graph-tracer: handle the leaf functions from trace_pipe
When one cats the trace file, the leaf functions are printed without brackets:
function();
whereas in the trace_pipe file we'll see the following:
function() {
}
This is because the ring_buffer handling is not the same between those two files.
On the trace file, when an entry is printed, the iterator advanced and then we can
check the next entry.
There is no iterator with trace_pipe, the current entry to print has been peeked
and not consumed. So checking the next entry will still return the current one while
we don't consume it.
This patch introduces a new value for the output callbacks to ask the tracing
core to not consume the current entry after printing it.
We need it because we will have to consume the current entry ourself to check
the next one.
Now the trace_pipe is able to handle well the leaf functions.
Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Acked-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
-rw-r--r-- | kernel/trace/trace_functions_graph.c | 48 |
1 files changed, 30 insertions, 18 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c index 88f8d9d80a93..782ec0fdf453 100644 --- a/kernel/trace/trace_functions_graph.c +++ b/kernel/trace/trace_functions_graph.c | |||
@@ -212,8 +212,8 @@ verif_pid(struct trace_seq *s, pid_t pid, int cpu, pid_t *last_pids_cpu) | |||
212 | return ret; | 212 | return ret; |
213 | } | 213 | } |
214 | 214 | ||
215 | static bool | 215 | static struct ftrace_graph_ret_entry * |
216 | trace_branch_is_leaf(struct trace_iterator *iter, | 216 | get_return_for_leaf(struct trace_iterator *iter, |
217 | struct ftrace_graph_ent_entry *curr) | 217 | struct ftrace_graph_ent_entry *curr) |
218 | { | 218 | { |
219 | struct ring_buffer_iter *ring_iter; | 219 | struct ring_buffer_iter *ring_iter; |
@@ -222,24 +222,33 @@ trace_branch_is_leaf(struct trace_iterator *iter, | |||
222 | 222 | ||
223 | ring_iter = iter->buffer_iter[iter->cpu]; | 223 | ring_iter = iter->buffer_iter[iter->cpu]; |
224 | 224 | ||
225 | if (!ring_iter) | 225 | /* First peek to compare current entry and the next one */ |
226 | return false; | 226 | if (ring_iter) |
227 | 227 | event = ring_buffer_iter_peek(ring_iter, NULL); | |
228 | event = ring_buffer_iter_peek(ring_iter, NULL); | 228 | else { |
229 | /* We need to consume the current entry to see the next one */ | ||
230 | ring_buffer_consume(iter->tr->buffer, iter->cpu, NULL); | ||
231 | event = ring_buffer_peek(iter->tr->buffer, iter->cpu, | ||
232 | NULL); | ||
233 | } | ||
229 | 234 | ||
230 | if (!event) | 235 | if (!event) |
231 | return false; | 236 | return NULL; |
232 | 237 | ||
233 | next = ring_buffer_event_data(event); | 238 | next = ring_buffer_event_data(event); |
234 | 239 | ||
235 | if (next->ent.type != TRACE_GRAPH_RET) | 240 | if (next->ent.type != TRACE_GRAPH_RET) |
236 | return false; | 241 | return NULL; |
237 | 242 | ||
238 | if (curr->ent.pid != next->ent.pid || | 243 | if (curr->ent.pid != next->ent.pid || |
239 | curr->graph_ent.func != next->ret.func) | 244 | curr->graph_ent.func != next->ret.func) |
240 | return false; | 245 | return NULL; |
241 | 246 | ||
242 | return true; | 247 | /* this is a leaf, now advance the iterator */ |
248 | if (ring_iter) | ||
249 | ring_buffer_read(ring_iter, NULL); | ||
250 | |||
251 | return next; | ||
243 | } | 252 | } |
244 | 253 | ||
245 | /* Signal a overhead of time execution to the output */ | 254 | /* Signal a overhead of time execution to the output */ |
@@ -376,18 +385,15 @@ static int print_graph_abs_time(u64 t, struct trace_seq *s) | |||
376 | /* Case of a leaf function on its call entry */ | 385 | /* Case of a leaf function on its call entry */ |
377 | static enum print_line_t | 386 | static enum print_line_t |
378 | print_graph_entry_leaf(struct trace_iterator *iter, | 387 | print_graph_entry_leaf(struct trace_iterator *iter, |
379 | struct ftrace_graph_ent_entry *entry, struct trace_seq *s) | 388 | struct ftrace_graph_ent_entry *entry, |
389 | struct ftrace_graph_ret_entry *ret_entry, struct trace_seq *s) | ||
380 | { | 390 | { |
381 | struct ftrace_graph_ret_entry *ret_entry; | ||
382 | struct ftrace_graph_ret *graph_ret; | 391 | struct ftrace_graph_ret *graph_ret; |
383 | struct ring_buffer_event *event; | ||
384 | struct ftrace_graph_ent *call; | 392 | struct ftrace_graph_ent *call; |
385 | unsigned long long duration; | 393 | unsigned long long duration; |
386 | int ret; | 394 | int ret; |
387 | int i; | 395 | int i; |
388 | 396 | ||
389 | event = ring_buffer_read(iter->buffer_iter[iter->cpu], NULL); | ||
390 | ret_entry = ring_buffer_event_data(event); | ||
391 | graph_ret = &ret_entry->ret; | 397 | graph_ret = &ret_entry->ret; |
392 | call = &entry->graph_ent; | 398 | call = &entry->graph_ent; |
393 | duration = graph_ret->rettime - graph_ret->calltime; | 399 | duration = graph_ret->rettime - graph_ret->calltime; |
@@ -457,7 +463,11 @@ print_graph_entry_nested(struct ftrace_graph_ent_entry *entry, | |||
457 | if (!ret) | 463 | if (!ret) |
458 | return TRACE_TYPE_PARTIAL_LINE; | 464 | return TRACE_TYPE_PARTIAL_LINE; |
459 | 465 | ||
460 | return TRACE_TYPE_HANDLED; | 466 | /* |
467 | * we already consumed the current entry to check the next one | ||
468 | * and see if this is a leaf. | ||
469 | */ | ||
470 | return TRACE_TYPE_NO_CONSUME; | ||
461 | } | 471 | } |
462 | 472 | ||
463 | static enum print_line_t | 473 | static enum print_line_t |
@@ -469,6 +479,7 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s, | |||
469 | pid_t *last_entry = iter->private; | 479 | pid_t *last_entry = iter->private; |
470 | struct trace_entry *ent = iter->ent; | 480 | struct trace_entry *ent = iter->ent; |
471 | struct ftrace_graph_ent *call = &field->graph_ent; | 481 | struct ftrace_graph_ent *call = &field->graph_ent; |
482 | struct ftrace_graph_ret_entry *leaf_ret; | ||
472 | 483 | ||
473 | /* Pid */ | 484 | /* Pid */ |
474 | if (verif_pid(s, ent->pid, cpu, last_entry) == TRACE_TYPE_PARTIAL_LINE) | 485 | if (verif_pid(s, ent->pid, cpu, last_entry) == TRACE_TYPE_PARTIAL_LINE) |
@@ -504,8 +515,9 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s, | |||
504 | return TRACE_TYPE_PARTIAL_LINE; | 515 | return TRACE_TYPE_PARTIAL_LINE; |
505 | } | 516 | } |
506 | 517 | ||
507 | if (trace_branch_is_leaf(iter, field)) | 518 | leaf_ret = get_return_for_leaf(iter, field); |
508 | return print_graph_entry_leaf(iter, field, s); | 519 | if (leaf_ret) |
520 | return print_graph_entry_leaf(iter, field, leaf_ret, s); | ||
509 | else | 521 | else |
510 | return print_graph_entry_nested(field, s, iter->ent->pid, cpu); | 522 | return print_graph_entry_nested(field, s, iter->ent->pid, cpu); |
511 | 523 | ||