diff options
author | Paul E. McKenney <paulmck@linux.vnet.ibm.com> | 2008-06-18 08:21:44 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-06-18 09:06:56 -0400 |
commit | d120f65f3aaf306c957bc4c82e510f5b0f1e9b27 (patch) | |
tree | 4b10376660bbfdb4ed8c79b17d0c1abc93b44089 /kernel | |
parent | 5af970a48f3ba0dd96a036b196c79dc923f28231 (diff) |
rcu: make rcutorture more vicious: add stutter feature
This patch takes a step towards making rcutorture more brutal by allowing
the test to be automatically periodically paused, with the default being
to run the test for five seconds then pause for five seconds and repeat.
This behavior can be controlled using a new "stutter" module parameter, so
that "stutter=0" gives the old default behavior of running continuously.
Starting and stopping rcutorture more heavily stresses RCU's interaction
with the scheduler, as well as exercising more paths through the
grace-period detection code.
Note that the default to "shuffle_interval" has also been adjusted from
5 seconds to 3 seconds to provide varying overlap with the "stutter"
interval.
I am still unable to provoke the failures that Alexey has been seeing,
even with this patch, but will be doing a few additional things to beef
up rcutorture.
Suggested-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/rcutorture.c | 59 |
1 files changed, 56 insertions, 3 deletions
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 0ca7e9b290b0..98ae7d168225 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c | |||
@@ -57,7 +57,8 @@ static int stat_interval; /* Interval between stats, in seconds. */ | |||
57 | /* Defaults to "only at end of test". */ | 57 | /* Defaults to "only at end of test". */ |
58 | static int verbose; /* Print more debug info. */ | 58 | static int verbose; /* Print more debug info. */ |
59 | static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */ | 59 | static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */ |
60 | static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/ | 60 | static int shuffle_interval = 3; /* Interval between shuffles (in sec)*/ |
61 | static int stutter = 5; /* Start/stop testing interval (in sec) */ | ||
61 | static char *torture_type = "rcu"; /* What RCU implementation to torture. */ | 62 | static char *torture_type = "rcu"; /* What RCU implementation to torture. */ |
62 | 63 | ||
63 | module_param(nreaders, int, 0444); | 64 | module_param(nreaders, int, 0444); |
@@ -72,6 +73,8 @@ module_param(test_no_idle_hz, bool, 0444); | |||
72 | MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs"); | 73 | MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs"); |
73 | module_param(shuffle_interval, int, 0444); | 74 | module_param(shuffle_interval, int, 0444); |
74 | MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles"); | 75 | MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles"); |
76 | module_param(stutter, int, 0444); | ||
77 | MODULE_PARM_DESC(stutter, "Number of seconds to run/halt test"); | ||
75 | module_param(torture_type, charp, 0444); | 78 | module_param(torture_type, charp, 0444); |
76 | MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)"); | 79 | MODULE_PARM_DESC(torture_type, "Type of RCU to torture (rcu, rcu_bh, srcu)"); |
77 | 80 | ||
@@ -91,6 +94,7 @@ static struct task_struct **fakewriter_tasks; | |||
91 | static struct task_struct **reader_tasks; | 94 | static struct task_struct **reader_tasks; |
92 | static struct task_struct *stats_task; | 95 | static struct task_struct *stats_task; |
93 | static struct task_struct *shuffler_task; | 96 | static struct task_struct *shuffler_task; |
97 | static struct task_struct *stutter_task; | ||
94 | 98 | ||
95 | #define RCU_TORTURE_PIPE_LEN 10 | 99 | #define RCU_TORTURE_PIPE_LEN 10 |
96 | 100 | ||
@@ -119,6 +123,8 @@ static atomic_t n_rcu_torture_mberror; | |||
119 | static atomic_t n_rcu_torture_error; | 123 | static atomic_t n_rcu_torture_error; |
120 | static struct list_head rcu_torture_removed; | 124 | static struct list_head rcu_torture_removed; |
121 | 125 | ||
126 | static int stutter_pause_test = 0; | ||
127 | |||
122 | /* | 128 | /* |
123 | * Allocate an element from the rcu_tortures pool. | 129 | * Allocate an element from the rcu_tortures pool. |
124 | */ | 130 | */ |
@@ -179,6 +185,13 @@ rcu_random(struct rcu_random_state *rrsp) | |||
179 | return swahw32(rrsp->rrs_state); | 185 | return swahw32(rrsp->rrs_state); |
180 | } | 186 | } |
181 | 187 | ||
188 | static void | ||
189 | rcu_stutter_wait(void) | ||
190 | { | ||
191 | while (stutter_pause_test) | ||
192 | schedule_timeout_interruptible(1); | ||
193 | } | ||
194 | |||
182 | /* | 195 | /* |
183 | * Operations vector for selecting different types of tests. | 196 | * Operations vector for selecting different types of tests. |
184 | */ | 197 | */ |
@@ -563,6 +576,7 @@ rcu_torture_writer(void *arg) | |||
563 | } | 576 | } |
564 | rcu_torture_current_version++; | 577 | rcu_torture_current_version++; |
565 | oldbatch = cur_ops->completed(); | 578 | oldbatch = cur_ops->completed(); |
579 | rcu_stutter_wait(); | ||
566 | } while (!kthread_should_stop() && !fullstop); | 580 | } while (!kthread_should_stop() && !fullstop); |
567 | VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping"); | 581 | VERBOSE_PRINTK_STRING("rcu_torture_writer task stopping"); |
568 | while (!kthread_should_stop()) | 582 | while (!kthread_should_stop()) |
@@ -586,6 +600,7 @@ rcu_torture_fakewriter(void *arg) | |||
586 | schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10); | 600 | schedule_timeout_uninterruptible(1 + rcu_random(&rand)%10); |
587 | udelay(rcu_random(&rand) & 0x3ff); | 601 | udelay(rcu_random(&rand) & 0x3ff); |
588 | cur_ops->sync(); | 602 | cur_ops->sync(); |
603 | rcu_stutter_wait(); | ||
589 | } while (!kthread_should_stop() && !fullstop); | 604 | } while (!kthread_should_stop() && !fullstop); |
590 | 605 | ||
591 | VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping"); | 606 | VERBOSE_PRINTK_STRING("rcu_torture_fakewriter task stopping"); |
@@ -641,6 +656,7 @@ rcu_torture_reader(void *arg) | |||
641 | preempt_enable(); | 656 | preempt_enable(); |
642 | cur_ops->readunlock(idx); | 657 | cur_ops->readunlock(idx); |
643 | schedule(); | 658 | schedule(); |
659 | rcu_stutter_wait(); | ||
644 | } while (!kthread_should_stop() && !fullstop); | 660 | } while (!kthread_should_stop() && !fullstop); |
645 | VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping"); | 661 | VERBOSE_PRINTK_STRING("rcu_torture_reader task stopping"); |
646 | while (!kthread_should_stop()) | 662 | while (!kthread_should_stop()) |
@@ -812,15 +828,34 @@ rcu_torture_shuffle(void *arg) | |||
812 | return 0; | 828 | return 0; |
813 | } | 829 | } |
814 | 830 | ||
831 | /* Cause the rcutorture test to "stutter", starting and stopping all | ||
832 | * threads periodically. | ||
833 | */ | ||
834 | static int | ||
835 | rcu_torture_stutter(void *arg) | ||
836 | { | ||
837 | VERBOSE_PRINTK_STRING("rcu_torture_stutter task started"); | ||
838 | do { | ||
839 | schedule_timeout_interruptible(stutter * HZ); | ||
840 | stutter_pause_test = 1; | ||
841 | if (!kthread_should_stop()) | ||
842 | schedule_timeout_interruptible(stutter * HZ); | ||
843 | stutter_pause_test = 0; | ||
844 | } while (!kthread_should_stop()); | ||
845 | VERBOSE_PRINTK_STRING("rcu_torture_stutter task stopping"); | ||
846 | return 0; | ||
847 | } | ||
848 | |||
815 | static inline void | 849 | static inline void |
816 | rcu_torture_print_module_parms(char *tag) | 850 | rcu_torture_print_module_parms(char *tag) |
817 | { | 851 | { |
818 | printk(KERN_ALERT "%s" TORTURE_FLAG | 852 | printk(KERN_ALERT "%s" TORTURE_FLAG |
819 | "--- %s: nreaders=%d nfakewriters=%d " | 853 | "--- %s: nreaders=%d nfakewriters=%d " |
820 | "stat_interval=%d verbose=%d test_no_idle_hz=%d " | 854 | "stat_interval=%d verbose=%d test_no_idle_hz=%d " |
821 | "shuffle_interval = %d\n", | 855 | "shuffle_interval=%d stutter=%d\n", |
822 | torture_type, tag, nrealreaders, nfakewriters, | 856 | torture_type, tag, nrealreaders, nfakewriters, |
823 | stat_interval, verbose, test_no_idle_hz, shuffle_interval); | 857 | stat_interval, verbose, test_no_idle_hz, shuffle_interval, |
858 | stutter); | ||
824 | } | 859 | } |
825 | 860 | ||
826 | static void | 861 | static void |
@@ -829,6 +864,11 @@ rcu_torture_cleanup(void) | |||
829 | int i; | 864 | int i; |
830 | 865 | ||
831 | fullstop = 1; | 866 | fullstop = 1; |
867 | if (stutter_task) { | ||
868 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_stutter task"); | ||
869 | kthread_stop(stutter_task); | ||
870 | } | ||
871 | stutter_task = NULL; | ||
832 | if (shuffler_task) { | 872 | if (shuffler_task) { |
833 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task"); | 873 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task"); |
834 | kthread_stop(shuffler_task); | 874 | kthread_stop(shuffler_task); |
@@ -1017,6 +1057,19 @@ rcu_torture_init(void) | |||
1017 | goto unwind; | 1057 | goto unwind; |
1018 | } | 1058 | } |
1019 | } | 1059 | } |
1060 | if (stutter < 0) | ||
1061 | stutter = 0; | ||
1062 | if (stutter) { | ||
1063 | /* Create the stutter thread */ | ||
1064 | stutter_task = kthread_run(rcu_torture_stutter, NULL, | ||
1065 | "rcu_torture_stutter"); | ||
1066 | if (IS_ERR(stutter_task)) { | ||
1067 | firsterr = PTR_ERR(stutter_task); | ||
1068 | VERBOSE_PRINTK_ERRSTRING("Failed to create stutter"); | ||
1069 | stutter_task = NULL; | ||
1070 | goto unwind; | ||
1071 | } | ||
1072 | } | ||
1020 | return 0; | 1073 | return 0; |
1021 | 1074 | ||
1022 | unwind: | 1075 | unwind: |