aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorFrederic Weisbecker <fweisbec@gmail.com>2008-11-25 18:57:25 -0500
committerIngo Molnar <mingo@elte.hu>2008-11-25 19:59:45 -0500
commit287b6e68ca7209caec40b2f44f837c580a413bae (patch)
treeb0867d75868f6049dc5747bd39fdae2d477dde66 /arch/x86
parentfb52607afcd0629776f1dc9e657647ceae81dd50 (diff)
tracing/function-return-tracer: set a more human readable output
Impact: feature This patch sets a C-like output for the function graph tracing. For this aim, we now call two handler for each function: one on the entry and one other on return. This way we can draw a well-ordered call stack. The pid of the previous trace is loosely stored to be compared against the one of the current trace to see if there were a context switch. Without this little feature, the call tree would seem broken at some locations. We could use the sched_tracer to capture these sched_events but this way of processing is much more simpler. 2 spaces have been chosen for indentation to fit the screen while deep calls. The time of execution in nanosecs is printed just after closed braces, it seems more easy this way to find the corresponding function. If the time was printed as a first column, it would be not so easy to find the corresponding function if it is called on a deep depth. I plan to output the return value but on 32 bits CPU, the return value can be 32 or 64, and its difficult to guess on which case we are. I don't know what would be the better solution on X86-32: only print eax (low-part) or even edx (high-part). Actually it's thee same problem when a function return a 8 bits value, the high part of eax could contain junk values... Here is an example of trace: sys_read() { fget_light() { } 526 vfs_read() { rw_verify_area() { security_file_permission() { cap_file_permission() { } 519 } 1564 } 2640 do_sync_read() { pipe_read() { __might_sleep() { } 511 pipe_wait() { prepare_to_wait() { } 760 deactivate_task() { dequeue_task() { dequeue_task_fair() { dequeue_entity() { update_curr() { update_min_vruntime() { } 504 } 1587 clear_buddies() { } 512 add_cfs_task_weight() { } 519 update_min_vruntime() { } 511 } 5602 dequeue_entity() { update_curr() { update_min_vruntime() { } 496 } 1631 clear_buddies() { } 496 update_min_vruntime() { } 527 } 4580 hrtick_update() { hrtick_start_fair() { } 488 } 1489 } 13700 } 14949 } 16016 msecs_to_jiffies() { } 496 put_prev_task_fair() { } 504 pick_next_task_fair() { } 489 pick_next_task_rt() { } 496 pick_next_task_fair() { } 489 pick_next_task_idle() { } 489 ------------8<---------- thread 4 ------------8<---------- finish_task_switch() { } 1203 do_softirq() { __do_softirq() { __local_bh_disable() { } 669 rcu_process_callbacks() { __rcu_process_callbacks() { cpu_quiet() { rcu_start_batch() { } 503 } 1647 } 3128 __rcu_process_callbacks() { } 542 } 5362 _local_bh_enable() { } 587 } 8880 } 9986 kthread_should_stop() { } 669 deactivate_task() { dequeue_task() { dequeue_task_fair() { dequeue_entity() { update_curr() { calc_delta_mine() { } 511 update_min_vruntime() { } 511 } 2813 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 'arch/x86')
-rw-r--r--arch/x86/kernel/ftrace.c32
1 files changed, 21 insertions, 11 deletions
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 3595a4c14aba..26b2d92d48b3 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -347,7 +347,7 @@ void ftrace_nmi_exit(void)
347 347
348/* Add a function return address to the trace stack on thread info.*/ 348/* Add a function return address to the trace stack on thread info.*/
349static int push_return_trace(unsigned long ret, unsigned long long time, 349static int push_return_trace(unsigned long ret, unsigned long long time,
350 unsigned long func) 350 unsigned long func, int *depth)
351{ 351{
352 int index; 352 int index;
353 353
@@ -365,21 +365,22 @@ static int push_return_trace(unsigned long ret, unsigned long long time,
365 current->ret_stack[index].ret = ret; 365 current->ret_stack[index].ret = ret;
366 current->ret_stack[index].func = func; 366 current->ret_stack[index].func = func;
367 current->ret_stack[index].calltime = time; 367 current->ret_stack[index].calltime = time;
368 *depth = index;
368 369
369 return 0; 370 return 0;
370} 371}
371 372
372/* Retrieve a function return address to the trace stack on thread info.*/ 373/* Retrieve a function return address to the trace stack on thread info.*/
373static void pop_return_trace(unsigned long *ret, unsigned long long *time, 374static void pop_return_trace(struct ftrace_graph_ret *trace, unsigned long *ret)
374 unsigned long *func, unsigned long *overrun)
375{ 375{
376 int index; 376 int index;
377 377
378 index = current->curr_ret_stack; 378 index = current->curr_ret_stack;
379 *ret = current->ret_stack[index].ret; 379 *ret = current->ret_stack[index].ret;
380 *func = current->ret_stack[index].func; 380 trace->func = current->ret_stack[index].func;
381 *time = current->ret_stack[index].calltime; 381 trace->calltime = current->ret_stack[index].calltime;
382 *overrun = atomic_read(&current->trace_overrun); 382 trace->overrun = atomic_read(&current->trace_overrun);
383 trace->depth = index;
383 current->curr_ret_stack--; 384 current->curr_ret_stack--;
384} 385}
385 386
@@ -390,12 +391,13 @@ static void pop_return_trace(unsigned long *ret, unsigned long long *time,
390unsigned long ftrace_return_to_handler(void) 391unsigned long ftrace_return_to_handler(void)
391{ 392{
392 struct ftrace_graph_ret trace; 393 struct ftrace_graph_ret trace;
393 pop_return_trace(&trace.ret, &trace.calltime, &trace.func, 394 unsigned long ret;
394 &trace.overrun); 395
396 pop_return_trace(&trace, &ret);
395 trace.rettime = cpu_clock(raw_smp_processor_id()); 397 trace.rettime = cpu_clock(raw_smp_processor_id());
396 ftrace_graph_function(&trace); 398 ftrace_graph_return(&trace);
397 399
398 return trace.ret; 400 return ret;
399} 401}
400 402
401/* 403/*
@@ -407,6 +409,7 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
407 unsigned long old; 409 unsigned long old;
408 unsigned long long calltime; 410 unsigned long long calltime;
409 int faulted; 411 int faulted;
412 struct ftrace_graph_ent trace;
410 unsigned long return_hooker = (unsigned long) 413 unsigned long return_hooker = (unsigned long)
411 &return_to_handler; 414 &return_to_handler;
412 415
@@ -452,8 +455,15 @@ void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr)
452 455
453 calltime = cpu_clock(raw_smp_processor_id()); 456 calltime = cpu_clock(raw_smp_processor_id());
454 457
455 if (push_return_trace(old, calltime, self_addr) == -EBUSY) 458 if (push_return_trace(old, calltime,
459 self_addr, &trace.depth) == -EBUSY) {
456 *parent = old; 460 *parent = old;
461 return;
462 }
463
464 trace.func = self_addr;
465 ftrace_graph_entry(&trace);
466
457} 467}
458 468
459#endif /* CONFIG_FUNCTION_GRAPH_TRACER */ 469#endif /* CONFIG_FUNCTION_GRAPH_TRACER */