v2 Documentation and rcutorture changes for 3.9
Subsystems (6)
cover v2 Documentation and rcutorture changes for 3.9
Hello!
The following are changes to documentation and rcutorture:
1. Export trace_clock_local() in order to allow rcutorture event
tracing to emit the time of the beginning of the RCU read-side critical section at the point where a failure is detected.
2. Reduce rcutorture's read-side tracing to include only failures,
thus cutting the number of events down to something reasonable (normally zero, in fact!).
3. Add atomic_xchg() to the list of atomic operations and memory
barriers, courtesy of Richard Braun.
4. Make rcutorture's shuffler task also shuffle recently added
rcutorture kthreads.
Changes since v1:
o Fixed build problem in #2 located by Randy Dunlap based on
diagnosis from Steven Rostedt.
o Added patch #4.
Thanx, Paul
b/Documentation/atomic_ops.txt | 2 + b/Documentation/memory-barriers.txt | 1 b/include/linux/rcupdate.h | 13 ++++++-- b/include/trace/events/rcu.h | 19 +++++++++--- b/kernel/rcupdate.c | 9 +++-- b/kernel/rcutorture.c | 55 ++++++++++++++++++++++++++++-------- b/kernel/trace/trace_clock.c | 1 b/lib/Kconfig.debug | 1 8 files changed, 79 insertions(+), 22 deletions(-)
PATCH 1/4 tracing: Export trace_clock_local()
From: "Paul E. McKenney" <[email protected]>
The rcutorture tests need to be able to trace the time of the beginning of an RCU read-side critical section, and thus need access to trace_clock_local(). This commit therefore adds a the needed EXPORT_SYMBOL_GPL().
--- kernel/trace/trace_clock.c | 1 + 1 files changed, 1 insertions(+), 0 deletions(-)
kernel/trace/trace_clock.c +1 -0
@@ -44,6 +44,7 @@ u64 notrace trace_clock_local(void)return clock; } +EXPORT_SYMBOL_GPL (trace_clock_local);/* * trace_clock(): 'between' trace clock. Not completely serialized,
Signature · 1 line
1.7.8
PATCH 4/4 rcu: Make rcutorture's shuffler task shuffle recently added tasks
From: "Paul E. McKenney" <[email protected]>
A number of kthreads have been added to rcutorture, but the shuffler task was not informed of them, and thus did not shuffle them. This commit therefore adds the requisite shuffling.
--- kernel/rcutorture.c | 24 ++++++++++++++++++++---- 1 files changed, 20 insertions(+), 4 deletions(-)
kernel/rcutorture.c +20 -4
@@ -846,7 +846,7 @@ static int rcu_torture_boost(void *arg)/* Wait for the next test interval. */ oldstarttime = boost_starttime;while (ULONG_CMP_LT (jiffies, oldstarttime)) { -schedule_timeout_uninterruptible (1 ); +schedule_timeout_interruptible (oldstarttime - jiffies);rcu_stutter_wait ("rcu_torture_boost" );if (kthread_should_stop () || fullstop !=FULLSTOP_DONTSTOP )
@@ -1318,19 +1318,35 @@ static void rcu_torture_shuffle_tasks(void)set_cpus_allowed_ptr (reader_tasks[i], shuffle_tmp_mask); } -if (fakewriter_tasks) {for (i =0 ; i < nfakewriters; i++)if (fakewriter_tasks[i])set_cpus_allowed_ptr (fakewriter_tasks[i], shuffle_tmp_mask); } -if (writer_task)set_cpus_allowed_ptr (writer_task, shuffle_tmp_mask); -if (stats_task)set_cpus_allowed_ptr (stats_task, shuffle_tmp_mask); +if (stutter_task) +set_cpus_allowed_ptr (stutter_task, shuffle_tmp_mask); +if (fqs_task) +set_cpus_allowed_ptr (fqs_task, shuffle_tmp_mask); +if (shutdown_task) +set_cpus_allowed_ptr (shutdown_task, shuffle_tmp_mask); +#ifdef CONFIG_HOTPLUG_CPU +if (onoff_task) +set_cpus_allowed_ptr (onoff_task, shuffle_tmp_mask); +#endif /* #ifdef CONFIG_HOTPLUG_CPU */ +if (stall_task) +set_cpus_allowed_ptr (stall_task, shuffle_tmp_mask); +if (barrier_cbs_tasks) +for (i =0 ; i < n_barrier_cbs; i++) +if (barrier_cbs_tasks[i]) +set_cpus_allowed_ptr (barrier_cbs_tasks[i], + shuffle_tmp_mask); +if (barrier_task) +set_cpus_allowed_ptr (barrier_task, shuffle_tmp_mask);if (rcu_idle_cpu ==-1 ) rcu_idle_cpu =num_online_cpus () -1 ;
Signature · 1 line
1.7.8
PATCH 3/4 Documentation: Memory barrier semantics of atomic_xchg()
In reply to Paul E. McKenneyFrom: Richard Braun <[email protected]>
Add atomic_xchg() to documentation for atomic operations and memory barriers.
--- Documentation/atomic_ops.txt | 2 ++ Documentation/memory-barriers.txt | 1 + 2 files changed, 3 insertions(+), 0 deletions(-)
Documentation/atomic_ops.txt +2 -0
@@ -253,6 +253,8 @@ This performs an atomic exchange operation on the atomic variable v, setting the given new value. It returns the old value that the atomic variable v had just before the operation. +atomic_xchg requires explicit memory barriers around the operation. + int atomic_cmpxchg(atomic_t *v, int old, int new); This performs an atomic compare exchange operation on the atomic value v,
Documentation/memory-barriers.txt +1 -0
@@ -1685,6 +1685,7 @@ explicit lock operations, described later). These include: xchg(); cmpxchg(); + atomic_xchg(); atomic_cmpxchg(); atomic_inc_return(); atomic_dec_return();
Signature · 1 line
1.7.8
PATCH 2/4 rcu: Reduce rcutorture tracing
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
Currently, rcutorture traces every read-side access. This can be problematic because even a two-minute rcutorture run on a two-CPU system can generate 28,853,363 reads. Normally, only a failing read is of interest, so this commit traces adjusts rcutorture's tracing to only trace failing reads. The resulting event tracing records the time and the ->completed value captured at the beginning of the RCU read-side critical section, allowing correlation with other event-tracing messages.
[ paulmck: Add fix to build problem located by Randy Dunlap based on
diagnosis by Steven Rostedt. ]
--- include/linux/rcupdate.h | 13 ++++++++++--- include/trace/events/rcu.h | 19 ++++++++++++++----- kernel/rcupdate.c | 9 ++++++--- kernel/rcutorture.c | 31 ++++++++++++++++++++++++------- lib/Kconfig.debug | 1 + 5 files changed, 55 insertions(+), 18 deletions(-)
include/linux/rcupdate.h +10 -3
@@ -53,7 +53,10 @@ extern int rcutorture_runnable; /* for sysctl */extern void rcutorture_record_test_transition (void );extern void rcutorture_record_progress (unsigned long vernum);extern void do_trace_rcu_torture_read (char *rcutorturename, -struct rcu_head *rhp); +struct rcu_head *rhp, +unsigned long secs, +unsigned long c_old, +unsigned long c);#else static inline void rcutorture_record_test_transition (void ) {
@@ -63,9 +66,13 @@ static inline void rcutorture_record_progress(unsigned long vernum) }#ifdef CONFIG_RCU_TRACE extern void do_trace_rcu_torture_read (char *rcutorturename, -struct rcu_head *rhp); +struct rcu_head *rhp, +unsigned long secs, +unsigned long c_old, +unsigned long c);#else -#define do_trace_rcu_torture_read (rcutorturename, rhp) do { } while (0) +#define do_trace_rcu_torture_read (rcutorturename, rhp, secs, c_old, c) \ + do { } while (0)#endif #endif
include/trace/events/rcu.h +14 -5
@@ -523,22 +523,30 @@ TRACE_EVENT(rcu_batch_end,*/ TRACE_EVENT (rcu_torture_read, - TP_PROTO(char *rcutorturename, struct rcu_head *rhp), + TP_PROTO(char *rcutorturename, struct rcu_head *rhp, + unsigned long secs, unsigned long c_old, unsigned long c), -TP_ARGS (rcutorturename, rhp), +TP_ARGS (rcutorturename, rhp, secs, c_old, c),TP_STRUCT__entry ( __field(char *, rcutorturename) __field(struct rcu_head *, rhp) + __field(unsigned long, secs) + __field(unsigned long, c_old) + __field(unsigned long, c) ),TP_fast_assign ( __entry->rcutorturename = rcutorturename; __entry->rhp = rhp; + __entry->secs = secs; + __entry->c_old = c_old; + __entry->c = c; ), -TP_printk ("%s torture read %p" , - __entry->rcutorturename, __entry->rhp) +TP_printk ("%s torture read %p %luus c: %lu %lu" , + __entry->rcutorturename, __entry->rhp, + __entry->secs, __entry->c_old, __entry->c) );/*
@@ -608,7 +616,8 @@ TRACE_EVENT(rcu_barrier,#define trace_rcu_invoke_kfree_callback (rcuname, rhp, offset) do { } while (0)#define trace_rcu_batch_end (rcuname, callbacks_invoked, cb, nr, iit, risk) \ do { } while (0) -#define trace_rcu_torture_read (rcutorturename, rhp) do { } while (0) +#define trace_rcu_torture_read (rcutorturename, rhp, secs, c_old, c) \ + do { } while (0)#define trace_rcu_barrier (name, s, cpu, cnt, done) do { } while (0)#endif /* #else #ifdef CONFIG_RCU_TRACE */
kernel/rcupdate.c +6 -3
@@ -404,11 +404,14 @@ EXPORT_SYMBOL_GPL(rcuhead_debug_descr);#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */ #if defined(CONFIG_TREE_RCU ) || defined(CONFIG_TREE_PREEMPT_RCU ) || defined(CONFIG_RCU_TRACE ) -void do_trace_rcu_torture_read (char *rcutorturename,struct rcu_head *rhp) +void do_trace_rcu_torture_read (char *rcutorturename,struct rcu_head *rhp, +unsigned long secs, +unsigned long c_old,unsigned long c) { -trace_rcu_torture_read (rcutorturename, rhp); +trace_rcu_torture_read (rcutorturename, rhp, secs, c_old, c); }EXPORT_SYMBOL_GPL (do_trace_rcu_torture_read);#else -#define do_trace_rcu_torture_read (rcutorturename, rhp) do { } while (0) +#define do_trace_rcu_torture_read (rcutorturename, rhp, secs, c_old, c) \ + do { } while (0)#endif
kernel/rcutorture.c +24 -7
@@ -46,6 +46,7 @@#include <linux/stat.h> #include <linux/srcu.h> #include <linux/slab.h> +#include <linux/trace_clock.h> #include <asm/byteorder.h> MODULE_LICENSE ("GPL" );
@@ -1028,7 +1029,6 @@ void rcutorture_trace_dump(void)return ;if (atomic_xchg (&beenhere,1 ) !=0 )return ; -do_trace_rcu_torture_read (cur_ops->name, (struct rcu_head *)~0UL );ftrace_dump (DUMP_ALL ); }
@@ -1042,13 +1042,16 @@ static void rcu_torture_timer(unsigned long unused) {int idx;int completed; +int completed_end;static DEFINE_RCU_RANDOM (rand);static DEFINE_SPINLOCK (rand_lock);struct rcu_torture *p;int pipe_count; +unsigned long long ts; idx = cur_ops->readlock (); completed = cur_ops->completed (); + ts =trace_clock_local (); p = rcu_dereference_check(rcu_torture_current, rcu_read_lock_bh_held() || rcu_read_lock_sched_held() ||
@@ -1058,7 +1061,6 @@ static void rcu_torture_timer(unsigned long unused) cur_ops->readunlock (idx);return ; } -do_trace_rcu_torture_read (cur_ops->name, &p->rtort_rcu);if (p->rtort_mbtest ==0 )atomic_inc (&n_rcu_torture_mberror);spin_lock (&rand_lock);
@@ -1071,10 +1073,16 @@ static void rcu_torture_timer(unsigned long unused)/* Should not happen, but... */ pipe_count =RCU_TORTURE_PIPE_LEN ; } -if (pipe_count >1 ) + completed_end = cur_ops->completed (); +if (pipe_count >1 ) { +unsigned long __maybe_unused ts_rem =do_div (ts,NSEC_PER_USEC ); + +do_trace_rcu_torture_read (cur_ops->name, &p->rtort_rcu, ts, + completed, completed_end);rcutorture_trace_dump (); + }__this_cpu_inc (rcu_torture_count[pipe_count]); - completed = cur_ops->completed () - completed; + completed = completed_end - completed;if (completed >RCU_TORTURE_PIPE_LEN ) {/* Should not happen, but... */ completed =RCU_TORTURE_PIPE_LEN ;
@@ -1094,11 +1102,13 @@ static int rcu_torture_reader(void *arg) {int completed; +int completed_end;int idx;DEFINE_RCU_RANDOM (rand);struct rcu_torture *p;int pipe_count;struct timer_list t; +unsigned long long ts;VERBOSE_PRINTK_STRING ("rcu_torture_reader task started" );set_user_nice (current,19 );
@@ -1112,6 +1122,7 @@ rcu_torture_reader(void *arg) } idx = cur_ops->readlock (); completed = cur_ops->completed (); + ts =trace_clock_local (); p = rcu_dereference_check(rcu_torture_current, rcu_read_lock_bh_held() || rcu_read_lock_sched_held() ||
@@ -1122,7 +1133,6 @@ rcu_torture_reader(void *arg)schedule_timeout_interruptible (HZ );continue ; } -do_trace_rcu_torture_read (cur_ops->name, &p->rtort_rcu);if (p->rtort_mbtest ==0 )atomic_inc (&n_rcu_torture_mberror); cur_ops->read_delay (&rand);
@@ -1132,10 +1142,17 @@ rcu_torture_reader(void *arg)/* Should not happen, but... */ pipe_count =RCU_TORTURE_PIPE_LEN ; } -if (pipe_count >1 ) + completed_end = cur_ops->completed (); +if (pipe_count >1 ) { +unsigned long __maybe_unused ts_rem = +do_div (ts,NSEC_PER_USEC ); + +do_trace_rcu_torture_read (cur_ops->name, &p->rtort_rcu, + ts, completed, completed_end);rcutorture_trace_dump (); + }__this_cpu_inc (rcu_torture_count[pipe_count]); - completed = cur_ops->completed () - completed; + completed = completed_end - completed;if (completed >RCU_TORTURE_PIPE_LEN ) {/* Should not happen, but... */ completed =RCU_TORTURE_PIPE_LEN ;
lib/Kconfig.debug +1 -0
@@ -1008,6 +1008,7 @@ config RCU_CPU_STALL_INFO config RCU_TRACE bool "Enable tracing for RCU" depends on DEBUG_KERNEL + select TRACE_CLOCK help This option provides tracing in RCU which presents stats in debugfs for debugging RCU implementation.
Signature · 1 line
1.7.8
Josh Triplett
maintainerRe: [PATCH tip/core/rcu 4/4] rcu: Make rcutorture's shuffler task shuffle recently added tasks
In reply to Paul E. McKenneyQuoted 7 lines · Paul E. McKenney
From: "Paul E. McKenney" <[email protected]>
A number of kthreads have been added to rcutorture, but the shuffler task was not informed of them, and thus did not shuffle them. This commit therefore adds the requisite shuffling.
Signed-off-by Paul E. McKenney <[email protected]>
This also makes an unrelated semantic change, and several unrelated whitespace changes.
Quoted 9 lines
--- kernel/rcutorture.c | 24 ++++++++++++++++++++---- 1 files changed, 20 insertions(+), 4 deletions(-)kernel/rcutorture.c +0
-0
kernel/rcutorture.c static int rcu_torture_boost(void *arg) · line 849
Quoted 5 lines
kernel/rcutorture.c +1
-1@@ -846,7 +846,7 @@ static int rcu_torture_boost(void *arg)/* Wait for the next test interval. */ oldstarttime = boost_starttime;while (ULONG_CMP_LT (jiffies, oldstarttime)) { -schedule_timeout_uninterruptible (1 ); +schedule_timeout_interruptible (oldstarttime - jiffies);
This change doesn't seem related, and the commit message doesn't explain it either. Could you split it out into a separate commit and document the rationale, please?
Quoted 8 lines
kernel/rcutorture.c +0
-1rcu_stutter_wait ("rcu_torture_boost" );if (kthread_should_stop () || fullstop !=FULLSTOP_DONTSTOP )@@ -1318,19 +1318,35 @@ static void rcu_torture_shuffle_tasks(void)set_cpus_allowed_ptr (reader_tasks[i], shuffle_tmp_mask); } -
kernel/rcutorture.c static void rcu_torture_shuffle_tasks(void) · line 1331
Quoted 10 lines
kernel/rcutorture.c +0
-2if (fakewriter_tasks) {for (i =0 ; i < nfakewriters; i++)if (fakewriter_tasks[i])set_cpus_allowed_ptr (fakewriter_tasks[i], shuffle_tmp_mask); } -if (writer_task)set_cpus_allowed_ptr (writer_task, shuffle_tmp_mask); -
These three whitespace changes seem unrelated as well.
Quoted 11 lines
kernel/rcutorture.c +9
-0if (stats_task)set_cpus_allowed_ptr (stats_task, shuffle_tmp_mask); +if (stutter_task) +set_cpus_allowed_ptr (stutter_task, shuffle_tmp_mask); +if (fqs_task) +set_cpus_allowed_ptr (fqs_task, shuffle_tmp_mask); +if (shutdown_task) +set_cpus_allowed_ptr (shutdown_task, shuffle_tmp_mask); +#ifdef CONFIG_HOTPLUG_CPU +if (onoff_task) +set_cpus_allowed_ptr (onoff_task, shuffle_tmp_mask);
kernel/rcutorture.c static void rcu_torture_shuffle_tasks(void) · line 1349
Quoted 10 lines
kernel/rcutorture.c +10
-0+#endif /* #ifdef CONFIG_HOTPLUG_CPU */ +if (stall_task) +set_cpus_allowed_ptr (stall_task, shuffle_tmp_mask); +if (barrier_cbs_tasks) +for (i =0 ; i < n_barrier_cbs; i++) +if (barrier_cbs_tasks[i]) +set_cpus_allowed_ptr (barrier_cbs_tasks[i], + shuffle_tmp_mask); +if (barrier_task) +set_cpus_allowed_ptr (barrier_task, shuffle_tmp_mask);
The rest of this seems fine.
- Josh Triplett
Re: [PATCH tip/core/rcu 4/4] rcu: Make rcutorture's shuffler task shuffle recently added tasks
Quoted 16 lines · Josh Triplett
Quoted 7 lines · Paul E. McKenney
From: "Paul E. McKenney" <[email protected]>
A number of kthreads have been added to rcutorture, but the shuffler task was not informed of them, and thus did not shuffle them. This commit therefore adds the requisite shuffling.
Signed-off-by Paul E. McKenney <[email protected]>This also makes an unrelated semantic change, and several unrelated whitespace changes.
Quoted 4 lines
--- kernel/rcutorture.c | 24 ++++++++++++++++++++---- 1 files changed, 20 insertions(+), 4 deletions(-)
Quoted 14 lines
kernel/rcutorture.c static int rcu_torture_boost(void *arg) · line 849
Quoted 10 lines
kernel/rcutorture.c +1
-1@@ -846,7 +846,7 @@ static int rcu_torture_boost(void *arg)/* Wait for the next test interval. */ oldstarttime = boost_starttime;while (ULONG_CMP_LT (jiffies, oldstarttime)) { -schedule_timeout_uninterruptible (1 ); +schedule_timeout_interruptible (oldstarttime - jiffies);This change doesn't seem related, and the commit message doesn't explain it either. Could you split it out into a separate commit and document the rationale, please?
Ah, it is related because the shuffling is trying to keep CPUs idle, which means that we don't want all the boost kthreads waking up every CPU every jiffy. I agree that this is not obvious, so I have updated the commit message to call this out.
Quoted 12 lines
Quoted 12 lines
kernel/rcutorture.c +0
-1rcu_stutter_wait ("rcu_torture_boost" );if (kthread_should_stop () || fullstop !=FULLSTOP_DONTSTOP )@@ -1318,19 +1318,35 @@ static void rcu_torture_shuffle_tasks(void)set_cpus_allowed_ptr (reader_tasks[i], shuffle_tmp_mask); } -if (fakewriter_tasks) {for (i =0 ; i < nfakewriters; i++)if (fakewriter_tasks[i]) set_cpus_allowed_ptr(fakewriter_tasks[i],
Quoted 8 lines
kernel/rcutorture.c static void rcu_torture_shuffle_tasks(void) · line 1331
Quoted 6 lines
kernel/rcutorture.c +0
-2shuffle_tmp_mask); } -if (writer_task)set_cpus_allowed_ptr (writer_task, shuffle_tmp_mask); -These three whitespace changes seem unrelated as well.
Some cleanup while in the neighborhood. ;-)
I added this to the commit message as well.
Thanx, Paul
Quoted 26 lines
Quoted 11 lines
kernel/rcutorture.c +9
-0if (stats_task)set_cpus_allowed_ptr (stats_task, shuffle_tmp_mask); +if (stutter_task) +set_cpus_allowed_ptr (stutter_task, shuffle_tmp_mask); +if (fqs_task) +set_cpus_allowed_ptr (fqs_task, shuffle_tmp_mask); +if (shutdown_task) +set_cpus_allowed_ptr (shutdown_task, shuffle_tmp_mask); +#ifdef CONFIG_HOTPLUG_CPU +if (onoff_task) +set_cpus_allowed_ptr (onoff_task, shuffle_tmp_mask);kernel/rcutorture.c static void rcu_torture_shuffle_tasks(void) · line 1349
Quoted 10 lines
kernel/rcutorture.c +10
-0+#endif /* #ifdef CONFIG_HOTPLUG_CPU */ +if (stall_task) +set_cpus_allowed_ptr (stall_task, shuffle_tmp_mask); +if (barrier_cbs_tasks) +for (i =0 ; i < n_barrier_cbs; i++) +if (barrier_cbs_tasks[i]) +set_cpus_allowed_ptr (barrier_cbs_tasks[i], + shuffle_tmp_mask); +if (barrier_task) +set_cpus_allowed_ptr (barrier_task, shuffle_tmp_mask);The rest of this seems fine.
- Josh Triplett