diff mbox

[RFC] tracing/rcu: Add trace_##name##__rcuidle() static tracepoint for inside rcu_idle_exit() sections

Message ID 1328563113.2200.39.camel@gandalf.stny.rr.com
State New
Headers show

Commit Message

Steven Rostedt Feb. 6, 2012, 9:18 p.m. UTC
As I have said, I may find a better solution than to create a
TRACE_EVENT_IDLE(), and I believe I have :-)

A added a new static inline function that lets *any* tracepoint be used
inside a rcu_idle_exit() section. And this also solves the problem where
the same tracepoint may be used inside a rcu_idle_exit() section as well
as outside of one.

I added a new tracepoint function with a "_rcuidle" extension. All
tracepoints can be used with either the normal "trace_foobar()"
function, or the "trace_foobar_rcuidle()" function when inside a
rcu_idle_exit() section.

Ideally, this patch would be broken up into two commits. The first would
change the tracepoint.h to introduce the new trace_foobar_rcuidle()
static inline, and the second patch would change the power tracepoints
to use this tracepoint function. For the RFC, I'm keeping it as a single
patch.

Another nice aspect about this patch is that "static inline"s are not
compiled into text when not used. So only the tracepoints that actually
use the _rcuidle() version will have them defined in the actual text
that is booted.

-- Steve

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

Comments

Josh Triplett Feb. 6, 2012, 10:05 p.m. UTC | #1
On Mon, Feb 06, 2012 at 04:18:33PM -0500, Steven Rostedt wrote:
> As I have said, I may find a better solution than to create a
> TRACE_EVENT_IDLE(), and I believe I have :-)
> 
> A added a new static inline function that lets *any* tracepoint be used
> inside a rcu_idle_exit() section. And this also solves the problem where
> the same tracepoint may be used inside a rcu_idle_exit() section as well
> as outside of one.
> 
> I added a new tracepoint function with a "_rcuidle" extension. All
> tracepoints can be used with either the normal "trace_foobar()"
> function, or the "trace_foobar_rcuidle()" function when inside a
> rcu_idle_exit() section.
> 
> Ideally, this patch would be broken up into two commits. The first would
> change the tracepoint.h to introduce the new trace_foobar_rcuidle()
> static inline, and the second patch would change the power tracepoints
> to use this tracepoint function. For the RFC, I'm keeping it as a single
> patch.
> 
> Another nice aspect about this patch is that "static inline"s are not
> compiled into text when not used. So only the tracepoints that actually
> use the _rcuidle() version will have them defined in the actual text
> that is booted.
> 
> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

This approach looks sensible to me, and it solves the problem of running
rcu_idle_{exit,enter} for disabled or compiled-out tracepoints.

One issue with the actual patch, though:

> --- linux-trace.git.orig/include/linux/tracepoint.h
> +++ linux-trace.git/include/linux/tracepoint.h
> @@ -114,7 +114,7 @@ static inline void tracepoint_synchroniz
>   * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just
>   * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto".
>   */
> -#define __DO_TRACE(tp, proto, args, cond)				\
> +#define __DO_TRACE(tp, proto, args, cond, pre, post)			\
>  	do {								\
>  		struct tracepoint_func *it_func_ptr;			\
>  		void *it_func;						\
> @@ -123,6 +123,7 @@ static inline void tracepoint_synchroniz
>  		if (!(cond))						\
>  			return;						\
>  		rcu_read_lock_sched_notrace();				\
> +		pre;							\
>  		it_func_ptr = rcu_dereference_sched((tp)->funcs);	\

This results in calling rcu_idle_exit after rcu_read_lock; it needs to
occur before.

- Josh Triplett
Paul E. McKenney Feb. 6, 2012, 11:38 p.m. UTC | #2
On Mon, Feb 06, 2012 at 04:18:33PM -0500, Steven Rostedt wrote:
> As I have said, I may find a better solution than to create a
> TRACE_EVENT_IDLE(), and I believe I have :-)
> 
> A added a new static inline function that lets *any* tracepoint be used
> inside a rcu_idle_exit() section. And this also solves the problem where
> the same tracepoint may be used inside a rcu_idle_exit() section as well
> as outside of one.
> 
> I added a new tracepoint function with a "_rcuidle" extension. All
> tracepoints can be used with either the normal "trace_foobar()"
> function, or the "trace_foobar_rcuidle()" function when inside a
> rcu_idle_exit() section.
> 
> Ideally, this patch would be broken up into two commits. The first would
> change the tracepoint.h to introduce the new trace_foobar_rcuidle()
> static inline, and the second patch would change the power tracepoints
> to use this tracepoint function. For the RFC, I'm keeping it as a single
> patch.
> 
> Another nice aspect about this patch is that "static inline"s are not
> compiled into text when not used. So only the tracepoints that actually
> use the _rcuidle() version will have them defined in the actual text
> that is booted.
> 
> -- Steve

Aside from the "pre;" below needing to precede rcu_read_lock_sched_notrace()
as Josh noted, this looks reasonable to me.

							Thanx, Paul

> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
> 
> Index: linux-trace.git/include/linux/tracepoint.h
> ===================================================================
> --- linux-trace.git.orig/include/linux/tracepoint.h
> +++ linux-trace.git/include/linux/tracepoint.h
> @@ -114,7 +114,7 @@ static inline void tracepoint_synchroniz
>   * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just
>   * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto".
>   */
> -#define __DO_TRACE(tp, proto, args, cond)				\
> +#define __DO_TRACE(tp, proto, args, cond, pre, post)			\
>  	do {								\
>  		struct tracepoint_func *it_func_ptr;			\
>  		void *it_func;						\
> @@ -123,6 +123,7 @@ static inline void tracepoint_synchroniz
>  		if (!(cond))						\
>  			return;						\
>  		rcu_read_lock_sched_notrace();				\
> +		pre;							\
>  		it_func_ptr = rcu_dereference_sched((tp)->funcs);	\
>  		if (it_func_ptr) {					\
>  			do {						\
> @@ -132,6 +133,7 @@ static inline void tracepoint_synchroniz
>  			} while ((++it_func_ptr)->func);		\
>  		}							\
>  		rcu_read_unlock_sched_notrace();			\
> +		post;							\
>  	} while (0)
> 
>  /*
> @@ -139,7 +141,7 @@ static inline void tracepoint_synchroniz
>   * not add unwanted padding between the beginning of the section and the
>   * structure. Force alignment to the same alignment as the section start.
>   */
> -#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args)	\
> +#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \
>  	extern struct tracepoint __tracepoint_##name;			\
>  	static inline void trace_##name(proto)				\
>  	{								\
> @@ -147,7 +149,17 @@ static inline void tracepoint_synchroniz
>  			__DO_TRACE(&__tracepoint_##name,		\
>  				TP_PROTO(data_proto),			\
>  				TP_ARGS(data_args),			\
> -				TP_CONDITION(cond));			\
> +				TP_CONDITION(cond),,);			\
> +	}								\
> +	static inline void trace_##name##_rcuidle(proto)		\
> +	{								\
> +		if (static_branch(&__tracepoint_##name.key))		\
> +			__DO_TRACE(&__tracepoint_##name,		\
> +				TP_PROTO(data_proto),			\
> +				TP_ARGS(data_args),			\
> +				TP_CONDITION(cond),			\
> +				rcu_idle_exit(),			\
> +				rcu_idle_enter());			\
>  	}								\
>  	static inline int						\
>  	register_trace_##name(void (*probe)(data_proto), void *data)	\
> @@ -190,7 +202,7 @@ static inline void tracepoint_synchroniz
>  	EXPORT_SYMBOL(__tracepoint_##name)
> 
>  #else /* !CONFIG_TRACEPOINTS */
> -#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args)	\
> +#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \
>  	static inline void trace_##name(proto)				\
>  	{ }								\
>  	static inline int						\
> Index: linux-trace.git/arch/x86/kernel/process.c
> ===================================================================
> --- linux-trace.git.orig/arch/x86/kernel/process.c
> +++ linux-trace.git/arch/x86/kernel/process.c
> @@ -377,8 +377,8 @@ static inline int hlt_use_halt(void)
>  void default_idle(void)
>  {
>  	if (hlt_use_halt()) {
> -		trace_power_start(POWER_CSTATE, 1, smp_processor_id());
> -		trace_cpu_idle(1, smp_processor_id());
> +		trace_power_start_rcuidle(POWER_CSTATE, 1, smp_processor_id());
> +		trace_cpu_idle_rcuidle(1, smp_processor_id());
>  		current_thread_info()->status &= ~TS_POLLING;
>  		/*
>  		 * TS_POLLING-cleared state must be visible before we
> @@ -391,7 +391,7 @@ void default_idle(void)
>  		else
>  			local_irq_enable();
>  		current_thread_info()->status |= TS_POLLING;
> -		trace_power_end(smp_processor_id());
> +		trace_power_end_rcuidle(smp_processor_id());
>  		trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
>  	} else {
>  		local_irq_enable();
> @@ -450,8 +450,8 @@ EXPORT_SYMBOL_GPL(cpu_idle_wait);
>  static void mwait_idle(void)
>  {
>  	if (!need_resched()) {
> -		trace_power_start(POWER_CSTATE, 1, smp_processor_id());
> -		trace_cpu_idle(1, smp_processor_id());
> +		trace_power_start_rcuidle(POWER_CSTATE, 1, smp_processor_id());
> +		trace_cpu_idle_rcuidle(1, smp_processor_id());
>  		if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR))
>  			clflush((void *)&current_thread_info()->flags);
> 
> @@ -461,8 +461,8 @@ static void mwait_idle(void)
>  			__sti_mwait(0, 0);
>  		else
>  			local_irq_enable();
> -		trace_power_end(smp_processor_id());
> -		trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
> +		trace_power_end_rcuidle(smp_processor_id());
> +		trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
>  	} else
>  		local_irq_enable();
>  }
> @@ -474,13 +474,13 @@ static void mwait_idle(void)
>   */
>  static void poll_idle(void)
>  {
> -	trace_power_start(POWER_CSTATE, 0, smp_processor_id());
> -	trace_cpu_idle(0, smp_processor_id());
> +	trace_power_start_rcuidle(POWER_CSTATE, 0, smp_processor_id());
> +	trace_cpu_idle_rcuidle(0, smp_processor_id());
>  	local_irq_enable();
>  	while (!need_resched())
>  		cpu_relax();
> -	trace_power_end(smp_processor_id());
> -	trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
> +	trace_power_end_rcuidle(smp_processor_id());
> +	trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
>  }
> 
>  /*
> 
>
Steven Rostedt Feb. 7, 2012, 12:36 a.m. UTC | #3
On Mon, 2012-02-06 at 14:05 -0800, Josh Triplett wrote:
> >   */
> > -#define __DO_TRACE(tp, proto, args, cond)				\
> > +#define __DO_TRACE(tp, proto, args, cond, pre, post)			\
> >  	do {								\
> >  		struct tracepoint_func *it_func_ptr;			\
> >  		void *it_func;						\
> > @@ -123,6 +123,7 @@ static inline void tracepoint_synchroniz
> >  		if (!(cond))						\
> >  			return;						\
> >  		rcu_read_lock_sched_notrace();				\
> > +		pre;							\
> >  		it_func_ptr = rcu_dereference_sched((tp)->funcs);	\
> 
> This results in calling rcu_idle_exit after rcu_read_lock; it needs to
> occur before.

Bah! Good catch. The fumes of my furnace must have been sending out some
strong narcotics. Yeah yeah, that's the reason for this mistake, and
I'll stand by it!

-- Steve
Steven Rostedt Feb. 7, 2012, 12:32 p.m. UTC | #4
On Mon, 2012-02-06 at 15:38 -0800, Paul E. McKenney wrote:

> Aside from the "pre;" below needing to precede rcu_read_lock_sched_notrace()
> as Josh noted, this looks reasonable to me.
> 

Does this mean I can add an Acked-by from you and Josh? Obviously with
the post "pre" change.

-- Steve
Paul E. McKenney Feb. 7, 2012, 2:11 p.m. UTC | #5
On Tue, Feb 07, 2012 at 07:32:56AM -0500, Steven Rostedt wrote:
> On Mon, 2012-02-06 at 15:38 -0800, Paul E. McKenney wrote:
> 
> > Aside from the "pre;" below needing to precede rcu_read_lock_sched_notrace()
> > as Josh noted, this looks reasonable to me.
> > 
> 
> Does this mean I can add an Acked-by from you and Josh? Obviously with
> the post "pre" change.

With the "pre" change,

Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>

							Thanx, Paul
Josh Triplett Feb. 7, 2012, 2:40 p.m. UTC | #6
On Tue, Feb 07, 2012 at 07:32:56AM -0500, Steven Rostedt wrote:
> On Mon, 2012-02-06 at 15:38 -0800, Paul E. McKenney wrote:
> 
> > Aside from the "pre;" below needing to precede rcu_read_lock_sched_notrace()
> > as Josh noted, this looks reasonable to me.
> > 
> 
> Does this mean I can add an Acked-by from you and Josh? Obviously with
> the post "pre" change.

With the pre change:

Reviewed-by: Josh Triplett <josh@joshtriplett.org>
Frederic Weisbecker Feb. 8, 2012, 1:57 p.m. UTC | #7
On Tue, Feb 07, 2012 at 06:11:42AM -0800, Paul E. McKenney wrote:
> On Tue, Feb 07, 2012 at 07:32:56AM -0500, Steven Rostedt wrote:
> > On Mon, 2012-02-06 at 15:38 -0800, Paul E. McKenney wrote:
> > 
> > > Aside from the "pre;" below needing to precede rcu_read_lock_sched_notrace()
> > > as Josh noted, this looks reasonable to me.
> > > 
> > 
> > Does this mean I can add an Acked-by from you and Josh? Obviously with
> > the post "pre" change.
> 
> With the "pre" change,
> 
> Acked-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>

Same for me! Good idea.

Acked-by: Frederic Weisbecker <fweisbec@gmail.com>
diff mbox

Patch

Index: linux-trace.git/include/linux/tracepoint.h
===================================================================
--- linux-trace.git.orig/include/linux/tracepoint.h
+++ linux-trace.git/include/linux/tracepoint.h
@@ -114,7 +114,7 @@  static inline void tracepoint_synchroniz
  * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just
  * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto".
  */
-#define __DO_TRACE(tp, proto, args, cond)				\
+#define __DO_TRACE(tp, proto, args, cond, pre, post)			\
 	do {								\
 		struct tracepoint_func *it_func_ptr;			\
 		void *it_func;						\
@@ -123,6 +123,7 @@  static inline void tracepoint_synchroniz
 		if (!(cond))						\
 			return;						\
 		rcu_read_lock_sched_notrace();				\
+		pre;							\
 		it_func_ptr = rcu_dereference_sched((tp)->funcs);	\
 		if (it_func_ptr) {					\
 			do {						\
@@ -132,6 +133,7 @@  static inline void tracepoint_synchroniz
 			} while ((++it_func_ptr)->func);		\
 		}							\
 		rcu_read_unlock_sched_notrace();			\
+		post;							\
 	} while (0)
 
 /*
@@ -139,7 +141,7 @@  static inline void tracepoint_synchroniz
  * not add unwanted padding between the beginning of the section and the
  * structure. Force alignment to the same alignment as the section start.
  */
-#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args)	\
+#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \
 	extern struct tracepoint __tracepoint_##name;			\
 	static inline void trace_##name(proto)				\
 	{								\
@@ -147,7 +149,17 @@  static inline void tracepoint_synchroniz
 			__DO_TRACE(&__tracepoint_##name,		\
 				TP_PROTO(data_proto),			\
 				TP_ARGS(data_args),			\
-				TP_CONDITION(cond));			\
+				TP_CONDITION(cond),,);			\
+	}								\
+	static inline void trace_##name##_rcuidle(proto)		\
+	{								\
+		if (static_branch(&__tracepoint_##name.key))		\
+			__DO_TRACE(&__tracepoint_##name,		\
+				TP_PROTO(data_proto),			\
+				TP_ARGS(data_args),			\
+				TP_CONDITION(cond),			\
+				rcu_idle_exit(),			\
+				rcu_idle_enter());			\
 	}								\
 	static inline int						\
 	register_trace_##name(void (*probe)(data_proto), void *data)	\
@@ -190,7 +202,7 @@  static inline void tracepoint_synchroniz
 	EXPORT_SYMBOL(__tracepoint_##name)
 
 #else /* !CONFIG_TRACEPOINTS */
-#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args)	\
+#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \
 	static inline void trace_##name(proto)				\
 	{ }								\
 	static inline int						\
Index: linux-trace.git/arch/x86/kernel/process.c
===================================================================
--- linux-trace.git.orig/arch/x86/kernel/process.c
+++ linux-trace.git/arch/x86/kernel/process.c
@@ -377,8 +377,8 @@  static inline int hlt_use_halt(void)
 void default_idle(void)
 {
 	if (hlt_use_halt()) {
-		trace_power_start(POWER_CSTATE, 1, smp_processor_id());
-		trace_cpu_idle(1, smp_processor_id());
+		trace_power_start_rcuidle(POWER_CSTATE, 1, smp_processor_id());
+		trace_cpu_idle_rcuidle(1, smp_processor_id());
 		current_thread_info()->status &= ~TS_POLLING;
 		/*
 		 * TS_POLLING-cleared state must be visible before we
@@ -391,7 +391,7 @@  void default_idle(void)
 		else
 			local_irq_enable();
 		current_thread_info()->status |= TS_POLLING;
-		trace_power_end(smp_processor_id());
+		trace_power_end_rcuidle(smp_processor_id());
 		trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
 	} else {
 		local_irq_enable();
@@ -450,8 +450,8 @@  EXPORT_SYMBOL_GPL(cpu_idle_wait);
 static void mwait_idle(void)
 {
 	if (!need_resched()) {
-		trace_power_start(POWER_CSTATE, 1, smp_processor_id());
-		trace_cpu_idle(1, smp_processor_id());
+		trace_power_start_rcuidle(POWER_CSTATE, 1, smp_processor_id());
+		trace_cpu_idle_rcuidle(1, smp_processor_id());
 		if (this_cpu_has(X86_FEATURE_CLFLUSH_MONITOR))
 			clflush((void *)&current_thread_info()->flags);
 
@@ -461,8 +461,8 @@  static void mwait_idle(void)
 			__sti_mwait(0, 0);
 		else
 			local_irq_enable();
-		trace_power_end(smp_processor_id());
-		trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
+		trace_power_end_rcuidle(smp_processor_id());
+		trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
 	} else
 		local_irq_enable();
 }
@@ -474,13 +474,13 @@  static void mwait_idle(void)
  */
 static void poll_idle(void)
 {
-	trace_power_start(POWER_CSTATE, 0, smp_processor_id());
-	trace_cpu_idle(0, smp_processor_id());
+	trace_power_start_rcuidle(POWER_CSTATE, 0, smp_processor_id());
+	trace_cpu_idle_rcuidle(0, smp_processor_id());
 	local_irq_enable();
 	while (!need_resched())
 		cpu_relax();
-	trace_power_end(smp_processor_id());
-	trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
+	trace_power_end_rcuidle(smp_processor_id());
+	trace_cpu_idle_rcuidle(PWR_EVENT_EXIT, smp_processor_id());
 }
 
 /*