2008-02-10 07:26:06

by Ingo Molnar

[permalink] [raw]
Subject: [13/19] ftrace: add tracing of context switches

From: Steven Rostedt <[email protected]>

This patch adds context switch tracing, of the format of:

_------=> CPU#
/ _-----=> irqs-off
| / _----=> need-resched
|| / _---=> hardirq/softirq
||| / _--=> preempt-depth
|||| /
||||| delay
cmd pid ||||| time | pid:prio:state
\ / ||||| \ | /
swapper-0 1d..3 137us+: 0:140:R --> 2912:120
sshd-2912 1d..3 216us+: 2912:120:S --> 0:140
swapper-0 1d..3 261us+: 0:140:R --> 2912:120
bash-2920 0d..3 267us+: 2920:120:S --> 0:140
sshd-2912 1d..3 330us!: 2912:120:S --> 0:140
swapper-0 1d..3 2389us+: 0:140:R --> 2847:120
yum-upda-2847 1d..3 2411us!: 2847:120:S --> 0:140
swapper-0 0d..3 11089us+: 0:140:R --> 3139:120
gdm-bina-3139 0d..3 11113us!: 3139:120:S --> 0:140
swapper-0 1d..3 102328us+: 0:140:R --> 2847:120
yum-upda-2847 1d..3 102348us!: 2847:120:S --> 0:140

"sched_switch" is added to /debugfs/tracing/available_tracers

Signed-off-by: Steven Rostedt <[email protected]>
Cc: Mathieu Desnoyers <[email protected]>
Signed-off-by: Ingo Molnar <[email protected]>
---
kernel/trace/Kconfig | 11 +++
kernel/trace/Makefile | 1
kernel/trace/trace_sched_switch.c | 125 ++++++++++++++++++++++++++++++++++++++
3 files changed, 137 insertions(+)

Index: linux/kernel/trace/Kconfig
===================================================================
--- linux.orig/kernel/trace/Kconfig
+++ linux/kernel/trace/Kconfig
@@ -13,6 +13,7 @@ config FTRACE
depends on DEBUG_KERNEL && HAVE_FTRACE
select FRAME_POINTER
select TRACING
+ select CONTEXT_SWITCH_TRACER
help
Enable the kernel to trace every kernel function. This is done
by using a compiler feature to insert a small, 5-byte No-Operation
@@ -21,3 +22,13 @@ config FTRACE
tracing is enabled by the administrator. If it's runtime disabled
(the bootup default), then the overhead of the instructions is very
small and not measurable even in micro-benchmarks.
+
+config CONTEXT_SWITCH_TRACER
+ bool "Trace process context switches"
+ depends on DEBUG_KERNEL
+ select TRACING
+ select MARKERS
+ help
+ This tracer gets called from the context switch and records
+ all switching of tasks.
+
Index: linux/kernel/trace/Makefile
===================================================================
--- linux.orig/kernel/trace/Makefile
+++ linux/kernel/trace/Makefile
@@ -1,6 +1,7 @@
obj-$(CONFIG_FTRACE) += libftrace.o

obj-$(CONFIG_TRACING) += trace.o
+obj-$(CONFIG_CONTEXT_SWITCH_TRACER) += trace_sched_switch.o
obj-$(CONFIG_FTRACE) += trace_functions.o

libftrace-y := ftrace.o
Index: linux/kernel/trace/trace_sched_switch.c
===================================================================
--- /dev/null
+++ linux/kernel/trace/trace_sched_switch.c
@@ -0,0 +1,125 @@
+/*
+ * trace context switch
+ *
+ * Copyright (C) 2007 Steven Rostedt <[email protected]>
+ *
+ */
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/debugfs.h>
+#include <linux/kallsyms.h>
+#include <linux/uaccess.h>
+#include <linux/marker.h>
+#include <linux/ftrace.h>
+
+#include "trace.h"
+
+static struct trace_array *ctx_trace;
+static int __read_mostly tracer_enabled;
+int __read_mostly tracing_sched_switch_enabled;
+
+static void notrace
+ctx_switch_func(struct task_struct *prev, struct task_struct *next)
+{
+ struct trace_array *tr = ctx_trace;
+ struct trace_array_cpu *data;
+ unsigned long flags;
+ long disabled;
+ int cpu;
+
+ if (!tracer_enabled)
+ return;
+
+ raw_local_irq_save(flags);
+ cpu = raw_smp_processor_id();
+ data = tr->data[cpu];
+ disabled = atomic_inc_return(&data->disabled);
+
+ if (likely(disabled == 1))
+ tracing_sched_switch_trace(tr, data, prev, next, flags);
+
+ atomic_dec(&data->disabled);
+ raw_local_irq_restore(flags);
+}
+
+void ftrace_ctx_switch(struct task_struct *prev, struct task_struct *next)
+{
+ tracing_record_cmdline(prev);
+
+ /*
+ * If tracer_switch_func only points to the local
+ * switch func, it still needs the ptr passed to it.
+ */
+ ctx_switch_func(prev, next);
+
+ /*
+ * Chain to the wakeup tracer (this is a NOP if disabled):
+ */
+ wakeup_sched_switch(prev, next);
+}
+
+static notrace void sched_switch_reset(struct trace_array *tr)
+{
+ int cpu;
+
+ tr->time_start = now(tr->cpu);
+
+ for_each_online_cpu(cpu)
+ tracing_reset(tr->data[cpu]);
+}
+
+static notrace void start_sched_trace(struct trace_array *tr)
+{
+ sched_switch_reset(tr);
+ tracer_enabled = 1;
+}
+
+static notrace void stop_sched_trace(struct trace_array *tr)
+{
+ tracer_enabled = 0;
+}
+
+static notrace void sched_switch_trace_init(struct trace_array *tr)
+{
+ ctx_trace = tr;
+
+ if (tr->ctrl)
+ start_sched_trace(tr);
+}
+
+static notrace void sched_switch_trace_reset(struct trace_array *tr)
+{
+ if (tr->ctrl)
+ stop_sched_trace(tr);
+}
+
+static void sched_switch_trace_ctrl_update(struct trace_array *tr)
+{
+ /* When starting a new trace, reset the buffers */
+ if (tr->ctrl)
+ start_sched_trace(tr);
+ else
+ stop_sched_trace(tr);
+}
+
+static struct tracer sched_switch_trace __read_mostly =
+{
+ .name = "sched_switch",
+ .init = sched_switch_trace_init,
+ .reset = sched_switch_trace_reset,
+ .ctrl_update = sched_switch_trace_ctrl_update,
+};
+
+__init static int init_sched_switch_trace(void)
+{
+ int ret;
+
+ ret = register_tracer(&sched_switch_trace);
+ if (ret)
+ return ret;
+
+ tracing_sched_switch_enabled = 1;
+
+ return ret;
+}
+device_initcall(init_sched_switch_trace);


2008-02-10 15:50:06

by Eugene Teo

[permalink] [raw]
Subject: [PATCH] ftrace: remove unused tracing_sched_switch_enabled

tracing_sched_switch_enabled isn't used anywhere.

Signed-off-by: Eugene Teo <[email protected]>
---
kernel/trace/trace.h | 1 -
kernel/trace/trace_sched_switch.c | 9 +--------
2 files changed, 1 insertions(+), 9 deletions(-)

diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index ac851b2..3173a93 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -138,7 +138,6 @@ void unregister_tracer(struct tracer *type);

extern unsigned long nsecs_to_usecs(unsigned long nsecs);

-extern int tracing_sched_switch_enabled;
extern unsigned long tracing_max_latency;
extern unsigned long tracing_thresh;

diff --git a/kernel/trace/trace_sched_switch.c b/kernel/trace/trace_sched_switch.c
index 412c226..c4e0134 100644
--- a/kernel/trace/trace_sched_switch.c
+++ b/kernel/trace/trace_sched_switch.c
@@ -16,7 +16,6 @@

static struct trace_array *ctx_trace;
static int __read_mostly tracer_enabled;
-int __read_mostly tracing_sched_switch_enabled;

static void notrace
ctx_switch_func(struct task_struct *prev, struct task_struct *next)
@@ -114,12 +113,6 @@ __init static int init_sched_switch_trace(void)
{
int ret;

- ret = register_tracer(&sched_switch_trace);
- if (ret)
- return ret;
-
- tracing_sched_switch_enabled = 1;
-
- return ret;
+ return register_tracer(&sched_switch_trace);
}
device_initcall(init_sched_switch_trace);

2008-02-10 15:55:37

by Eugene Teo

[permalink] [raw]
Subject: Re: [PATCH] ftrace: remove unused tracing_sched_switch_enabled

<quote sender="Eugene Teo">
> tracing_sched_switch_enabled isn't used anywhere.
>
> Signed-off-by: Eugene Teo <[email protected]>

Sorry, I forgot to remove the variable declaration. Here's a resend:

tracing_sched_switch_enabled isn't used anywhere.

Signed-off-by: Eugene Teo <[email protected]>
---
kernel/trace/trace.h | 1 -
kernel/trace/trace_sched_switch.c | 11 +----------
2 files changed, 1 insertions(+), 11 deletions(-)

diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index ac851b2..3173a93 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -138,7 +138,6 @@ void unregister_tracer(struct tracer *type);

extern unsigned long nsecs_to_usecs(unsigned long nsecs);

-extern int tracing_sched_switch_enabled;
extern unsigned long tracing_max_latency;
extern unsigned long tracing_thresh;

diff --git a/kernel/trace/trace_sched_switch.c b/kernel/trace/trace_sched_switch.c
index 412c226..3e4771d 100644
--- a/kernel/trace/trace_sched_switch.c
+++ b/kernel/trace/trace_sched_switch.c
@@ -16,7 +16,6 @@

static struct trace_array *ctx_trace;
static int __read_mostly tracer_enabled;
-int __read_mostly tracing_sched_switch_enabled;

static void notrace
ctx_switch_func(struct task_struct *prev, struct task_struct *next)
@@ -112,14 +111,6 @@ static struct tracer sched_switch_trace __read_mostly =

__init static int init_sched_switch_trace(void)
{
- int ret;
-
- ret = register_tracer(&sched_switch_trace);
- if (ret)
- return ret;
-
- tracing_sched_switch_enabled = 1;
-
- return ret;
+ return register_tracer(&sched_switch_trace);
}
device_initcall(init_sched_switch_trace);

2008-02-11 10:13:35

by Ingo Molnar

[permalink] [raw]
Subject: Re: [PATCH] ftrace: remove unused tracing_sched_switch_enabled


* Eugene Teo <[email protected]> wrote:

> <quote sender="Eugene Teo">
> > tracing_sched_switch_enabled isn't used anywhere.
> >
> > Signed-off-by: Eugene Teo <[email protected]>
>
> Sorry, I forgot to remove the variable declaration. Here's a resend:
>
> tracing_sched_switch_enabled isn't used anywhere.

thanks, applied.

Ingo