[tip/core/rcu,16/86] rcu: make rcutorture version numbers available through debugfs

Message ID 1304256126-26015-16-git-send-email-paulmck@linux.vnet.ibm.com
State New
Headers show

Commit Message

Paul E. McKenney May 1, 2011, 1:20 p.m.
From: Paul E. McKenney <paul.mckenney@linaro.org>

It is not possible to accurately correlate rcutorture output with that
of debugfs.  This patch therefore adds a debugfs file that prints out
the rcutorture version number, permitting easy correlation.

Signed-off-by: Paul E. McKenney <paul.mckenney@linaro.org>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
---
 include/linux/rcupdate.h |   13 ++++++++++++-
 include/linux/rcutree.h  |    3 +++
 kernel/rcutorture.c      |    8 +++++---
 kernel/rcutree.c         |   37 +++++++++++++++++++++++++++++++++++++
 kernel/rcutree_trace.c   |   28 ++++++++++++++++++++++++++++
 5 files changed, 85 insertions(+), 4 deletions(-)

Comments

Josh Triplett May 1, 2011, 3:29 p.m. | #1
On Sun, May 01, 2011 at 06:20:56AM -0700, Paul E. McKenney wrote:
> From: Paul E. McKenney <paul.mckenney@linaro.org>
> 
> It is not possible to accurately correlate rcutorture output with that
> of debugfs.  This patch therefore adds a debugfs file that prints out
> the rcutorture version number, permitting easy correlation.

You can't accurately correlate debugfs values with each
other, either, right?  The rcutorture version number can change between
accesses to different debugfs files.

- Josh Triplett
Paul E. McKenney May 2, 2011, 8:30 a.m. | #2
On Sun, May 01, 2011 at 08:29:03AM -0700, Josh Triplett wrote:
> On Sun, May 01, 2011 at 06:20:56AM -0700, Paul E. McKenney wrote:
> > From: Paul E. McKenney <paul.mckenney@linaro.org>
> > 
> > It is not possible to accurately correlate rcutorture output with that
> > of debugfs.  This patch therefore adds a debugfs file that prints out
> > the rcutorture version number, permitting easy correlation.
> 
> You can't accurately correlate debugfs values with each
> other, either, right?  The rcutorture version number can change between
> accesses to different debugfs files.

True, but this is OK given the use case.

The problem that I used to have was that an automated test run would get
a grace-period hang somewhere in the middle of a long run.  Now, in a
grace-period hang, most of the interesting debugfs output is static,
so it is not necessary to line them up exactly.  All that is needed is
for the corellation to be good enough for me to ignore the debugfs
output that came a long time before the hang started.

Also, if there is an RCU grace-period hang, the rcutorture version number
will stop changing once it has the entire array waiting for a grace period,
which normally happens in a few seconds.

Make sense, or am I missing your point?

							Thanx, Paul
Josh Triplett May 2, 2011, 5:39 p.m. | #3
On Mon, May 02, 2011 at 01:30:24AM -0700, Paul E. McKenney wrote:
> On Sun, May 01, 2011 at 08:29:03AM -0700, Josh Triplett wrote:
> > On Sun, May 01, 2011 at 06:20:56AM -0700, Paul E. McKenney wrote:
> > > From: Paul E. McKenney <paul.mckenney@linaro.org>
> > > 
> > > It is not possible to accurately correlate rcutorture output with that
> > > of debugfs.  This patch therefore adds a debugfs file that prints out
> > > the rcutorture version number, permitting easy correlation.
> > 
> > You can't accurately correlate debugfs values with each
> > other, either, right?  The rcutorture version number can change between
> > accesses to different debugfs files.
> 
> True, but this is OK given the use case.
> 
> The problem that I used to have was that an automated test run would get
> a grace-period hang somewhere in the middle of a long run.  Now, in a
> grace-period hang, most of the interesting debugfs output is static,
> so it is not necessary to line them up exactly.  All that is needed is
> for the corellation to be good enough for me to ignore the debugfs
> output that came a long time before the hang started.
> 
> Also, if there is an RCU grace-period hang, the rcutorture version number
> will stop changing once it has the entire array waiting for a grace period,
> which normally happens in a few seconds.
> 
> Make sense, or am I missing your point?

Makes sense.

- Josh Triplett

Patch

diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index ff422d2..9e169c2 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -47,6 +47,18 @@ 
 extern int rcutorture_runnable; /* for sysctl */
 #endif /* #ifdef CONFIG_RCU_TORTURE_TEST */
 
+#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU)
+extern void rcutorture_record_test_transition(void);
+extern void rcutorture_record_progress(unsigned long vernum);
+#else
+static inline void rcutorture_record_test_transition(void)
+{
+}
+static inline void rcutorture_record_progress(unsigned long vernum)
+{
+}
+#endif
+
 #define UINT_CMP_GE(a, b)	(UINT_MAX / 2 >= (a) - (b))
 #define UINT_CMP_LT(a, b)	(UINT_MAX / 2 < (a) - (b))
 #define ULONG_CMP_GE(a, b)	(ULONG_MAX / 2 >= (a) - (b))
@@ -68,7 +80,6 @@  extern void call_rcu_sched(struct rcu_head *head,
 extern void synchronize_sched(void);
 extern void rcu_barrier_bh(void);
 extern void rcu_barrier_sched(void);
-extern int sched_expedited_torture_stats(char *page);
 
 static inline void __rcu_read_lock_bh(void)
 {
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
index 3a93348..284dad1 100644
--- a/include/linux/rcutree.h
+++ b/include/linux/rcutree.h
@@ -58,9 +58,12 @@  static inline void synchronize_rcu_bh_expedited(void)
 
 extern void rcu_barrier(void);
 
+extern unsigned long rcutorture_testseq;
+extern unsigned long rcutorture_vernum;
 extern long rcu_batches_completed(void);
 extern long rcu_batches_completed_bh(void);
 extern long rcu_batches_completed_sched(void);
+
 extern void rcu_force_quiescent_state(void);
 extern void rcu_bh_force_quiescent_state(void);
 extern void rcu_sched_force_quiescent_state(void);
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
index 62ec8ee6..735d172 100644
--- a/kernel/rcutorture.c
+++ b/kernel/rcutorture.c
@@ -131,7 +131,7 @@  struct rcu_torture {
 
 static LIST_HEAD(rcu_torture_freelist);
 static struct rcu_torture __rcu *rcu_torture_current;
-static long rcu_torture_current_version;
+static unsigned long rcu_torture_current_version;
 static struct rcu_torture rcu_tortures[10 * RCU_TORTURE_PIPE_LEN];
 static DEFINE_SPINLOCK(rcu_torture_lock);
 static DEFINE_PER_CPU(long [RCU_TORTURE_PIPE_LEN + 1], rcu_torture_count) =
@@ -886,7 +886,7 @@  rcu_torture_writer(void *arg)
 			old_rp->rtort_pipe_count++;
 			cur_ops->deferred_free(old_rp);
 		}
-		rcu_torture_current_version++;
+		rcutorture_record_progress(++rcu_torture_current_version);
 		oldbatch = cur_ops->completed();
 		rcu_stutter_wait("rcu_torture_writer");
 	} while (!kthread_should_stop() && fullstop == FULLSTOP_DONTSTOP);
@@ -1066,7 +1066,7 @@  rcu_torture_printk(char *page)
 	}
 	cnt += sprintf(&page[cnt], "%s%s ", torture_type, TORTURE_FLAG);
 	cnt += sprintf(&page[cnt],
-		       "rtc: %p ver: %ld tfle: %d rta: %d rtaf: %d rtf: %d "
+		       "rtc: %p ver: %lu tfle: %d rta: %d rtaf: %d rtf: %d "
 		       "rtmbe: %d rtbke: %ld rtbre: %ld "
 		       "rtbf: %ld rtb: %ld nt: %ld",
 		       rcu_torture_current,
@@ -1329,6 +1329,7 @@  rcu_torture_cleanup(void)
 	int i;
 
 	mutex_lock(&fullstop_mutex);
+	rcutorture_record_test_transition();
 	if (fullstop == FULLSTOP_SHUTDOWN) {
 		printk(KERN_WARNING /* but going down anyway, so... */
 		       "Concurrent 'rmmod rcutorture' and shutdown illegal!\n");
@@ -1622,6 +1623,7 @@  rcu_torture_init(void)
 		}
 	}
 	register_reboot_notifier(&rcutorture_shutdown_nb);
+	rcutorture_record_test_transition();
 	mutex_unlock(&fullstop_mutex);
 	return 0;
 
diff --git a/kernel/rcutree.c b/kernel/rcutree.c
index a591694..c1f5434 100644
--- a/kernel/rcutree.c
+++ b/kernel/rcutree.c
@@ -102,6 +102,18 @@  static void invoke_rcu_cpu_kthread(void);
 #define RCU_KTHREAD_PRIO 1	/* RT priority for per-CPU kthreads. */
 
 /*
+ * Track the rcutorture test sequence number and the update version
+ * number within a given test.  The rcutorture_testseq is incremented
+ * on every rcutorture module load and unload, so has an odd value
+ * when a test is running.  The rcutorture_vernum is set to zero
+ * when rcutorture starts and is incremented on each rcutorture update.
+ * These variables enable correlating rcutorture output with the
+ * RCU tracing information.
+ */
+unsigned long rcutorture_testseq;
+unsigned long rcutorture_vernum;
+
+/*
  * Return true if an RCU grace period is in progress.  The ACCESS_ONCE()s
  * permit this function to be invoked without holding the root rcu_node
  * structure's ->lock, but of course results can be subject to change.
@@ -193,6 +205,31 @@  void rcu_bh_force_quiescent_state(void)
 EXPORT_SYMBOL_GPL(rcu_bh_force_quiescent_state);
 
 /*
+ * Record the number of times rcutorture tests have been initiated and
+ * terminated.  This information allows the debugfs tracing stats to be
+ * correlated to the rcutorture messages, even when the rcutorture module
+ * is being repeatedly loaded and unloaded.  In other words, we cannot
+ * store this state in rcutorture itself.
+ */
+void rcutorture_record_test_transition(void)
+{
+	rcutorture_testseq++;
+	rcutorture_vernum = 0;
+}
+EXPORT_SYMBOL_GPL(rcutorture_record_test_transition);
+
+/*
+ * Record the number of writer passes through the current rcutorture test.
+ * This is also used to correlate debugfs tracing stats with the rcutorture
+ * messages.
+ */
+void rcutorture_record_progress(unsigned long vernum)
+{
+	rcutorture_vernum++;
+}
+EXPORT_SYMBOL_GPL(rcutorture_record_progress);
+
+/*
  * Force a quiescent state for RCU-sched.
  */
 void rcu_sched_force_quiescent_state(void)
diff --git a/kernel/rcutree_trace.c b/kernel/rcutree_trace.c
index fc40e89..3baa235 100644
--- a/kernel/rcutree_trace.c
+++ b/kernel/rcutree_trace.c
@@ -394,6 +394,29 @@  static const struct file_operations rcu_pending_fops = {
 	.release = single_release,
 };
 
+static int show_rcutorture(struct seq_file *m, void *unused)
+{
+	seq_printf(m, "rcutorture test sequence: %lu %s\n",
+		   rcutorture_testseq >> 1,
+		   (rcutorture_testseq & 0x1) ? "(test in progress)" : "");
+	seq_printf(m, "rcutorture update version number: %lu\n",
+		   rcutorture_vernum);
+	return 0;
+}
+
+static int rcutorture_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, show_rcutorture, NULL);
+}
+
+static const struct file_operations rcutorture_fops = {
+	.owner = THIS_MODULE,
+	.open = rcutorture_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = single_release,
+};
+
 static struct dentry *rcudir;
 
 static int __init rcutree_trace_init(void)
@@ -430,6 +453,11 @@  static int __init rcutree_trace_init(void)
 						NULL, &rcu_pending_fops);
 	if (!retval)
 		goto free_out;
+
+	retval = debugfs_create_file("rcutorture", 0444, rcudir,
+						NULL, &rcutorture_fops);
+	if (!retval)
+		goto free_out;
 	return 0;
 free_out:
 	debugfs_remove_recursive(rcudir);