diff options
-rw-r--r-- | Documentation/RCU/torture.txt | 8 | ||||
-rw-r--r-- | kernel/rcutorture.c | 59 |
2 files changed, 63 insertions, 4 deletions
diff --git a/Documentation/RCU/torture.txt b/Documentation/RCU/torture.txt index 2967a65269d8..02b3d14c0209 100644 --- a/Documentation/RCU/torture.txt +++ b/Documentation/RCU/torture.txt | |||
@@ -46,9 +46,15 @@ stat_interval The number of seconds between output of torture | |||
46 | 46 | ||
47 | shuffle_interval | 47 | shuffle_interval |
48 | The number of seconds to keep the test threads affinitied | 48 | The number of seconds to keep the test threads affinitied |
49 | to a particular subset of the CPUs, defaults to 5 seconds. | 49 | to a particular subset of the CPUs, defaults to 3 seconds. |
50 | Used in conjunction with test_no_idle_hz. | 50 | Used in conjunction with test_no_idle_hz. |
51 | 51 | ||
52 | stutter The length of time to run the test before pausing for this | ||
53 | same period of time. Defaults to "stutter=5", so as | ||
54 | to run and pause for (roughly) five-second intervals. | ||
55 | Specifying "stutter=0" causes the test to run continuously | ||
56 | without pausing, which is the old default behavior. | ||
57 | |||
52 | test_no_idle_hz Whether or not to test the ability of RCU to operate in | 58 | test_no_idle_hz Whether or not to test the ability of RCU to operate in |
53 | a kernel that disables the scheduling-clock interrupt to | 59 | a kernel that disables the scheduling-clock interrupt to |
54 | idle CPUs. Boolean parameter, "1" to test, "0" otherwise. | 60 | idle CPUs. Boolean parameter, "1" to test, "0" otherwise. |
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: |