[RFD PATCH 4/4] cpu: measure time taken by subsystem notifiers duringcpu-hotplug

From: Gautham R Shenoy
Date: Tue Jun 16 2009 - 01:40:20 EST


Place tracepoints at appropriate places to profile the time consumed by the
notifiers and the core-cpu-hotplug operations.

Change the notifier chain api to pass private data which can be used for
filtering out the trace results.

Signed-off-by: Gautham R Shenoy <ego@xxxxxxxxxx>
---
include/trace/notifier_trace.h | 32 ++++++++++++++++++++++++++++++++
kernel/cpu.c | 11 +++++++++++
kernel/notifier.c | 23 ++++++++++++++++++-----
3 files changed, 61 insertions(+), 5 deletions(-)
create mode 100644 include/trace/notifier_trace.h

diff --git a/include/trace/notifier_trace.h b/include/trace/notifier_trace.h
new file mode 100644
index 0000000..1591a40
--- /dev/null
+++ b/include/trace/notifier_trace.h
@@ -0,0 +1,32 @@
+#ifndef _HOTPLUG_CPU_TRACE_H_
+#define _HOTPLUG_CPU_TRACE_H_
+
+#include <linux/tracepoint.h>
+#include <linux/notifier.h>
+
+DECLARE_TRACE(hotplug_notifier_event_start,
+ TP_PROTO(void *notifier_call, unsigned int val,
+ void *chain_head),
+ TP_ARGS(notifier_call, val, chain_head));
+
+DECLARE_TRACE(hotplug_notifier_event_stop,
+ TP_PROTO(void *notifier_call, unsigned int val,
+ void *chain_head),
+ TP_ARGS(notifier_call, val, chain_head));
+
+DECLARE_TRACE(stop_machine_event_start,
+ TP_PROTO(void),
+ TP_ARGS());
+
+DECLARE_TRACE(stop_machine_event_stop,
+ TP_PROTO(void),
+ TP_ARGS());
+
+DECLARE_TRACE(cpu_up_event_start,
+ TP_PROTO(void),
+ TP_ARGS());
+
+DECLARE_TRACE(cpu_up_event_stop,
+ TP_PROTO(void),
+ TP_ARGS());
+#endif
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 2b5d4e0..256a3e4 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -14,6 +14,7 @@
#include <linux/kthread.h>
#include <linux/stop_machine.h>
#include <linux/mutex.h>
+#include <trace/notifier_trace.h>

#ifdef CONFIG_SMP
/* Serializes the updates to cpu_online_mask, cpu_present_mask */
@@ -190,6 +191,9 @@ static int __ref take_cpu_down(void *_param)
return 0;
}

+DEFINE_TRACE(stop_machine_event_start);
+DEFINE_TRACE(stop_machine_event_stop);
+
/* Requires cpu_add_remove_lock to be held */
static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
{
@@ -229,7 +233,9 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
set_cpus_allowed_ptr(current,
cpumask_of(cpumask_any_but(cpu_online_mask, cpu)));

+ trace_stop_machine_event_start();
err = __stop_machine(take_cpu_down, &tcd_param, cpumask_of(cpu));
+ trace_stop_machine_event_stop();
if (err) {
/* CPU didn't die: tell everyone. Can't complain. */
if (raw_notifier_call_chain(&cpu_chain, CPU_DOWN_FAILED | mod,
@@ -327,6 +333,9 @@ int __ref cpu_down(unsigned int cpu)
EXPORT_SYMBOL(cpu_down);
#endif /*CONFIG_HOTPLUG_CPU*/

+DEFINE_TRACE(cpu_up_event_start);
+DEFINE_TRACE(cpu_up_event_stop);
+
/* Requires cpu_add_remove_lock to be held */
static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
{
@@ -349,7 +358,9 @@ static int __cpuinit _cpu_up(unsigned int cpu, int tasks_frozen)
}

/* Arch-specific enabling code. */
+ trace_cpu_up_event_start();
ret = __cpu_up(cpu);
+ trace_cpu_up_event_stop();
if (ret != 0)
goto out_notify;
BUG_ON(!cpu_online(cpu));
diff --git a/kernel/notifier.c b/kernel/notifier.c
index 61d5aa5..5729035 100644
--- a/kernel/notifier.c
+++ b/kernel/notifier.c
@@ -5,6 +5,7 @@
#include <linux/rcupdate.h>
#include <linux/vmalloc.h>
#include <linux/reboot.h>
+#include <trace/notifier_trace.h>

/*
* Notifier list for kernel code which wants to be called
@@ -59,6 +60,9 @@ static int notifier_chain_unregister(struct notifier_block **nl,
return -ENOENT;
}

+DEFINE_TRACE(hotplug_notifier_event_start);
+DEFINE_TRACE(hotplug_notifier_event_stop);
+
/**
* notifier_call_chain - Informs the registered notifiers about an event.
* @nl: Pointer to head of the blocking notifier chain
@@ -68,12 +72,16 @@ static int notifier_chain_unregister(struct notifier_block **nl,
* value of this parameter is -1.
* @nr_calls: Records the number of notifications sent. Don't care
* value of this field is NULL.
+ * @chain_head: Pointer to the head of the notifier chain. We cast it as
+ * void * to allow different kinds of notifier chains to
+ * pass the value of their chain heads.
* @returns: notifier_call_chain returns the value returned by the
* last notifier function called.
*/
static int __kprobes notifier_call_chain(struct notifier_block **nl,
unsigned long val, void *v,
- int nr_to_call, int *nr_calls)
+ int nr_to_call, int *nr_calls,
+ void *chain_head)
{
int ret = NOTIFY_DONE;
struct notifier_block *nb, *next_nb;
@@ -90,7 +98,11 @@ static int __kprobes notifier_call_chain(struct notifier_block **nl,
continue;
}
#endif
+ trace_hotplug_notifier_event_start((void *)(nb->notifier_call),
+ val, (void *)chain_head);
ret = nb->notifier_call(nb, val, v);
+ trace_hotplug_notifier_event_stop((void *)(nb->notifier_call),
+ val, (void *) chain_head);

if (nr_calls)
(*nr_calls)++;
@@ -179,7 +191,7 @@ int __kprobes __atomic_notifier_call_chain(struct atomic_notifier_head *nh,
int ret;

rcu_read_lock();
- ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
+ ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls, nh);
rcu_read_unlock();
return ret;
}
@@ -312,7 +324,7 @@ int __blocking_notifier_call_chain(struct blocking_notifier_head *nh,
if (rcu_dereference(nh->head)) {
down_read(&nh->rwsem);
ret = notifier_call_chain(&nh->head, val, v, nr_to_call,
- nr_calls);
+ nr_calls, nh);
up_read(&nh->rwsem);
}
return ret;
@@ -388,7 +400,8 @@ int __raw_notifier_call_chain(struct raw_notifier_head *nh,
unsigned long val, void *v,
int nr_to_call, int *nr_calls)
{
- return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
+ return notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls,
+ nh);
}
EXPORT_SYMBOL_GPL(__raw_notifier_call_chain);

@@ -491,7 +504,7 @@ int __srcu_notifier_call_chain(struct srcu_notifier_head *nh,
int idx;

idx = srcu_read_lock(&nh->srcu);
- ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls);
+ ret = notifier_call_chain(&nh->head, val, v, nr_to_call, nr_calls, nh);
srcu_read_unlock(&nh->srcu, idx);
return ret;
}

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/