On Mon, Aug 21, 2006 at 03:25:42PM -0700, Josh Triplett wrote:
> rcutorture currently has one writer and an arbitrary number of readers. To
> better exercise some of the code paths in RCU, add fake writer threads which
> call the synchronize function for the RCU variant in a loop, with a delay
> between calls to arrange for different numbers of writers running in parallel.
Looks like a very good addition to the torturing of RCU!!!
Acked-by: Paul E. McKenney <[email protected]>
> Signed-off-by: Josh Triplett <[email protected]>
> ---
> This revised patch incorporates Adrian Bunk's suggestion to make
> rcu_bh_torture_synchronize() static, and adds the previously missing
> Signed-Off-By noticed by Andrew Morton. Please replace the -mm patch
> "rcu-add-fake-writers-to-rcutorture.patch" with this one.
>
> I've tested rcutorture with this patch against classic RCU, the _bh
> variant, and SRCU. In the SRCU case, I used a systemtap script to
> confirm that the fakewriters do trigger the early return case in
> synchronize_srcu().
>
> Documentation/RCU/torture.txt | 9 +++
> kernel/rcutorture.c | 109 +++++++++++++++++++++++++++++++++++++++--
> 2 files changed, 113 insertions(+), 5 deletions(-)
>
> diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt
> index 2174bad..2180ef9 100644
> --- a/Documentation/RCU/torture.txt
> +++ b/Documentation/RCU/torture.txt
> @@ -28,6 +28,15 @@ nreaders This is the number of RCU readi
> To properly exercise RCU implementations with preemptible
> read-side critical sections.
>
> +nfakewriters This is the number of RCU fake writer threads to run. Fake
> + writer threads repeatedly use the synchronous "wait for
> + current readers" function of the interface selected by
> + torture_type, with a delay between calls to allow for various
> + different numbers of writers running in parallel.
> + nfakewriters defaults to 4, which provides enough parallelism
> + to trigger special cases caused by multiple writers, such as
> + the synchronize_srcu() early return optimization.
> +
> stat_interval The number of seconds between output of torture
> statistics (via printk()). Regardless of the interval,
> statistics are printed when the module is unloaded.
> diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c
> index 43d6d4f..e045021 100644
> --- a/kernel/rcutorture.c
> +++ b/kernel/rcutorture.c
> @@ -15,9 +15,10 @@
> * along with this program; if not, write to the Free Software
> * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
> *
> - * Copyright (C) IBM Corporation, 2005
> + * Copyright (C) IBM Corporation, 2005, 2006
> *
> * Authors: Paul E. McKenney <[email protected]>
> + * Josh Triplett <[email protected]>
> *
> * See also: Documentation/RCU/torture.txt
> */
> @@ -47,9 +48,11 @@ #include <linux/stat.h>
> #include <linux/srcu.h>
>
> MODULE_LICENSE("GPL");
> -MODULE_AUTHOR("Paul E. McKenney <[email protected]>");
> +MODULE_AUTHOR("Paul E. McKenney <[email protected]> and "
> + "Josh Triplett <[email protected]>");
>
> static int nreaders = -1; /* # reader threads, defaults to 2*ncpus */
> +static int nfakewriters = 4; /* # fake writer threads */
> static int stat_interval; /* Interval between stats, in seconds. */
> /* Defaults to "only at end of test". */
> static int verbose; /* Print more debug info. */
> @@ -59,6 +62,8 @@ static char *torture_type = "rcu"; /* Wh
>
> module_param(nreaders, int, 0);
> MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
> +module_param(nfakewriters, int, 0);
> +MODULE_PARM_DESC(nfakewriters, "Number of RCU fake writer threads");
> module_param(stat_interval, int, 0);
> MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
> module_param(verbose, bool, 0);
> @@ -82,6 +87,7 @@ static char printk_buf[4096];
>
> static int nrealreaders;
> static struct task_struct *writer_task;
> +static struct task_struct **fakewriter_tasks;
> static struct task_struct **reader_tasks;
> static struct task_struct *stats_task;
> static struct task_struct *shuffler_task;
> @@ -186,6 +192,7 @@ struct rcu_torture_ops {
> void (*readunlock)(int idx);
> int (*completed)(void);
> void (*deferredfree)(struct rcu_torture *p);
> + void (*sync)(void);
> int (*stats)(char *page);
> char *name;
> };
> @@ -258,6 +265,7 @@ static struct rcu_torture_ops rcu_ops =
> .readunlock = rcu_torture_read_unlock,
> .completed = rcu_torture_completed,
> .deferredfree = rcu_torture_deferred_free,
> + .sync = synchronize_rcu,
> .stats = NULL,
> .name = "rcu"
> };
> @@ -287,6 +295,28 @@ static void rcu_bh_torture_deferred_free
> call_rcu_bh(&p->rtort_rcu, rcu_torture_cb);
> }
>
> +struct rcu_bh_torture_synchronize {
> + struct rcu_head head;
> + struct completion completion;
> +};
> +
> +static void rcu_bh_torture_wakeme_after_cb(struct rcu_head *head)
> +{
> + struct rcu_bh_torture_synchronize *rcu;
> +
> + rcu = container_of(head, struct rcu_bh_torture_synchronize, head);
> + complete(&rcu->completion);
> +}
> +
> +static void rcu_bh_torture_synchronize(void)
> +{
> + struct rcu_bh_torture_synchronize rcu;
> +
> + init_completion(&rcu.completion);
> + call_rcu_bh(&rcu.head, rcu_bh_torture_wakeme_after_cb);
> + wait_for_completion(&rcu.completion);
> +}
> +
> static struct rcu_torture_ops rcu_bh_ops = {
> .init = NULL,
> .cleanup = NULL,
> @@ -295,6 +325,7 @@ static struct rcu_torture_ops rcu_bh_ops
> .readunlock = rcu_bh_torture_read_unlock,
> .completed = rcu_bh_torture_completed,
> .deferredfree = rcu_bh_torture_deferred_free,
> + .sync = rcu_bh_torture_synchronize,
> .stats = NULL,
> .name = "rcu_bh"
> };
> @@ -367,6 +398,11 @@ static void srcu_torture_deferred_free(s
> }
> }
>
> +static void srcu_torture_synchronize(void)
> +{
> + synchronize_srcu(&srcu_ctl);
> +}
> +
> static int srcu_torture_stats(char *page)
> {
> int cnt = 0;
> @@ -392,6 +428,7 @@ static struct rcu_torture_ops srcu_ops =
> .readunlock = srcu_torture_read_unlock,
> .completed = srcu_torture_completed,
> .deferredfree = srcu_torture_deferred_free,
> + .sync = srcu_torture_synchronize,
> .stats = srcu_torture_stats,
> .name = "srcu"
> };
> @@ -444,6 +481,30 @@ rcu_torture_writer(void *arg)
> }
>
> /*
> + * RCU torture fake writer kthread. Repeatedly calls sync, with a random
> + * delay between calls.
> + */
> +static int
> +rcu_torture_fakewriter(void *arg)
> +{
> + DEFINE_RCU_RANDOM(rand);
> +
> + VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task started");
> + set_user_nice(current, 19);
> +
> + do {
> + schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10);
> + udelay(rcu_random(&rand) & 0x3ff);
> + cur_ops->sync();
> + } while (!kthread_should_stop() && !fullstop);
> +
> + VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping");
> + while (!kthread_should_stop())
> + schedule_timeout_uninterruptible(1);
> + return 0;
> +}
> +
> +/*
> * RCU torture reader kthread. Repeatedly dereferences rcu_torture_current,
> * incrementing the corresponding element of the pipeline array. The
> * counter in the element should never be greater than 1, otherwise, the
> @@ -621,6 +682,12 @@ static void rcu_torture_shuffle_tasks(vo
> set_cpus_allowed(reader_tasks[i], tmp_mask);
> }
>
> + if (fakewriter_tasks != NULL) {
> + for (i = 0; i < nfakewriters; i++)
> + if (fakewriter_tasks[i])
> + set_cpus_allowed(fakewriter_tasks[i], tmp_mask);
> + }
> +
> if (writer_task)
> set_cpus_allowed(writer_task, tmp_mask);
>
> @@ -654,11 +721,12 @@ rcu_torture_shuffle(void *arg)
> static inline void
> rcu_torture_print_module_parms(char *tag)
> {
> - printk(KERN_ALERT "%s" TORTURE_FLAG "--- %s: nreaders=%d "
> + printk(KERN_ALERT "%s" TORTURE_FLAG
> + "--- %s: nreaders=%d nfakewriters=%d "
> "stat_interval=%d verbose=%d test_no_idle_hz=%d "
> "shuffle_interval = %d\n",
> - torture_type, tag, nrealreaders, stat_interval, verbose,
> - test_no_idle_hz, shuffle_interval);
> + torture_type, tag, nrealreaders, nfakewriters,
> + stat_interval, verbose, test_no_idle_hz, shuffle_interval);
> }
>
> static void
> @@ -693,6 +761,19 @@ rcu_torture_cleanup(void)
> }
> rcu_torture_current = NULL;
>
> + if (fakewriter_tasks != NULL) {
> + for (i = 0; i < nfakewriters; i++) {
> + if (fakewriter_tasks[i] != NULL) {
> + VERBOSE_PRINTK_STRING(
> + "Stopping rcu_torture_fakewriter task");
> + kthread_stop(fakewriter_tasks[i]);
> + }
> + fakewriter_tasks[i] = NULL;
> + }
> + kfree(fakewriter_tasks);
> + fakewriter_tasks = NULL;
> + }
> +
> if (stats_task != NULL) {
> VERBOSE_PRINTK_STRING("Stopping rcu_torture_stats task");
> kthread_stop(stats_task);
> @@ -780,6 +861,24 @@ rcu_torture_init(void)
> writer_task = NULL;
> goto unwind;
> }
> + fakewriter_tasks = kzalloc(nfakewriters * sizeof(fakewriter_tasks[0]),
> + GFP_KERNEL);
> + if (fakewriter_tasks == NULL) {
> + VERBOSE_PRINTK_ERRSTRING("out of memory");
> + firsterr = -ENOMEM;
> + goto unwind;
> + }
> + for (i = 0; i < nfakewriters; i++) {
> + VERBOSE_PRINTK_STRING("Creating rcu_torture_fakewriter task");
> + fakewriter_tasks[i] = kthread_run(rcu_torture_fakewriter, NULL,
> + "rcu_torture_fakewriter");
> + if (IS_ERR(fakewriter_tasks[i])) {
> + firsterr = PTR_ERR(fakewriter_tasks[i]);
> + VERBOSE_PRINTK_ERRSTRING("Failed to create fakewriter");
> + fakewriter_tasks[i] = NULL;
> + goto unwind;
> + }
> + }
> reader_tasks = kzalloc(nrealreaders * sizeof(reader_tasks[0]),
> GFP_KERNEL);
> if (reader_tasks == NULL) {
> --
> 1.4.1.1
>
>
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
[Index of Archives]
[Kernel Newbies]
[Netfilter]
[Bugtraq]
[Photo]
[Stuff]
[Gimp]
[Yosemite News]
[MIPS Linux]
[ARM Linux]
[Linux Security]
[Linux RAID]
[Video 4 Linux]
[Linux for the blind]
[Linux Resources]