[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <493C7058.4060709@gmail.com>
Date: Mon, 08 Dec 2008 01:54:48 +0100
From: Frederic Weisbecker <fweisbec@...il.com>
To: Ingo Molnar <mingo@...e.hu>
CC: Steven Rostedt <rostedt@...dmis.org>,
Peter Zijlstra <a.p.zijlstra@...llo.nl>,
Linux Kernel <linux-kernel@...r.kernel.org>
Subject: [PATCH 1/2] tracing/function-graph-tracer: signal interrupts entry/exit
points on outpout
Impact: provide interrupt detection on output
Suggested by Ingo.
If a hardirq is raised, we want it to be signaled on output, so this patch
adds two arrows on the output to find entry and exit points of a hardirq.
Unfortunately, there are many interrupt entrypoints and these can be differents
from one arch to another.
The approach here is one of the easiest, but doesn't shine by its scalability:
we have an array of the interrupt entrypoints names that we compare with the
symbol of the current traced function, if it matches, we draw the arrow.
Ie:
1) | unlock_buffer() {
1) | wake_up_bit() {
1) | bit_waitqueue() {
1) 0.872 us | __phys_addr();
1) 2.722 us | }
1) | __wake_up_bit() {
=================>
1) | do_IRQ() {
1) | exit_idle() {
1) | irq_enter() {
1) 0.790 us | idle_cpu();
1) 2.346 us | }
1) | handle_edge_irq() {
1) 1.098 us | _spin_lock();
1) | ack_apic_edge() {
1) 0.722 us | irq_complete_move();
1) 0.737 us | move_native_irq();
1) 0.707 us | native_apic_mem_write();
1) 5.249 us | }
1) 0.879 us | _spin_unlock();
1) | handle_IRQ_event() {
1) | timer_interrupt() {
1) | tick_handle_oneshot_broadcast() {
1) 1.165 us | _spin_lock();
1) | ktime_get() {
1) | ktime_get_ts() {
1) | getnstimeofday() {
1) 1.782 us | read_hpet();
1) 3.542 us | }
1) 0.744 us | set_normalized_timespec();
1) 6.640 us | }
1) 8.226 us | }
1) | tick_do_broadcast() {
1) | lapic_timer_broadcast() {
1) 0.879 us | flat_send_IPI_mask();
1) 2.467 us | }
1) 4.045 us | }
1) 0.864 us | _spin_unlock();
1) + 18.431 us | }
1) + 20.047 us | }
1) + 21.611 us | }
1) 0.940 us | note_interrupt();
1) 1.008 us | _spin_lock();
1) 0.992 us | _spin_unlock();
1) + 38.711 us | }
1) | irq_exit() {
1) 0.752 us | idle_cpu();
1) 2.609 us | }
1) + 48.952 us | }
<=================
1) + 55.314 us | }
1) + 60.983 us | }
1) + 62.976 us | }
1) + 64.984 us | }
Signed-off-by: Frederic Weisbecker <fweisbec@...il.com>
---
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 1b43086..26b4d6a 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -324,6 +324,24 @@ int __init ftrace_dyn_arch_init(void *data)
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+/* Used during output to find the interrupts entry/exit points */
+const char *ftrace_graph_irq_entries[] = {
+ "smp_call_function_single_interrupt",
+ "xen_call_function_single_interrupt",
+ "wrapper_smp_local_timer_interrupt",
+ "smp_irq_move_cleanup_interrupt",
+ "smp_call_function_interrupt",
+ "xen_call_function_interrupt",
+ "smp_apic_timer_interrupt",
+ "uv_bau_message_interrupt",
+ "mce_threshold_interrupt",
+ "smp_spurious_interrupt",
+ "smp_thermal_interrupt",
+ "smp_error_interrupt",
+ "do_IRQ",
+ NULL
+};
+
#ifdef CONFIG_DYNAMIC_FTRACE
extern void ftrace_graph_call(void);
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 11cac81..36065e8 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -411,6 +411,9 @@ static inline void unpause_graph_tracing(void)
{
atomic_dec(¤t->tracing_graph_pause);
}
+
+/* Contains the entrypoints to hardirq (arch defined) */
+extern const char *ftrace_graph_irq_entries[];
#else
#define __notrace_funcgraph
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index 32b7fb9..7ea446d 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -10,6 +10,8 @@
#include <linux/uaccess.h>
#include <linux/ftrace.h>
#include <linux/fs.h>
+#include <linux/module.h>
+#include <linux/kallsyms.h>
#include "trace.h"
@@ -64,6 +66,31 @@ static void graph_trace_reset(struct trace_array *tr)
unregister_ftrace_graph();
}
+/* Signal enter into or exit from an interrupt */
+static enum print_line_t
+print_graph_interrupt(struct trace_seq *s, unsigned long addr,
+ enum trace_type type)
+{
+ char symbol[KSYM_NAME_LEN];
+ const char *arrow;
+ int ret;
+ int i;
+
+ kallsyms_lookup(addr, NULL, NULL, NULL, symbol);
+ for (i = 0; ftrace_graph_irq_entries[i]; i++)
+ if (!strcmp(symbol, ftrace_graph_irq_entries[i])) {
+ if (type == TRACE_GRAPH_ENT)
+ arrow = " =================>\n";
+ else
+ arrow = " <=================\n";
+ ret = trace_seq_printf(s, arrow);
+ if (!ret)
+ return TRACE_TYPE_PARTIAL_LINE;
+ break;
+ }
+ return TRACE_TYPE_HANDLED;
+}
+
static inline int log10_cpu(int nb)
{
if (nb / 100)
@@ -385,6 +412,10 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
int ret;
struct trace_entry *ent = iter->ent;
+ ret = print_graph_interrupt(s, field->graph_ent.func, TRACE_GRAPH_ENT);
+ if (ret == TRACE_TYPE_PARTIAL_LINE)
+ return TRACE_TYPE_PARTIAL_LINE;
+
/* Pid */
if (verif_pid(s, ent->pid, cpu) == TRACE_TYPE_PARTIAL_LINE)
return TRACE_TYPE_PARTIAL_LINE;
@@ -474,6 +505,11 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
if (!ret)
return TRACE_TYPE_PARTIAL_LINE;
}
+
+ ret = print_graph_interrupt(s, trace->func, TRACE_GRAPH_RET);
+ if (ret == TRACE_TYPE_PARTIAL_LINE)
+ return TRACE_TYPE_PARTIAL_LINE;
+
return TRACE_TYPE_HANDLED;
}
--
1.6.0.4
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Powered by blists - more mailing lists