forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PATCH] RCU: add fake writers to rcutorture
rcutorture currently has one writer and an arbitrary number of readers. To better exercise some of the code paths in RCU implementations, 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. [[email protected]: cleanup] Acked-by: Paul McKenney <[email protected]> Cc: Dipkanar Sarma <[email protected]> Signed-off-by: Josh Triplett <[email protected]> Signed-off-by: Adrian Bunk <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
- Loading branch information
Josh Triplett
authored and
Linus Torvalds
committed
Oct 4, 2006
1 parent
75cfef3
commit b772e1d
Showing
2 changed files
with
113 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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/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"; /* What to torture: rcu, rcu_bh, srcu. */ | |
|
||
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(struct rcu_torture *p) | |
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(struct rcu_torture *p) | |
} | ||
} | ||
|
||
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" | ||
}; | ||
|
@@ -443,6 +480,30 @@ rcu_torture_writer(void *arg) | |
return 0; | ||
} | ||
|
||
/* | ||
* 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 | ||
|
@@ -621,6 +682,12 @@ static void rcu_torture_shuffle_tasks(void) | |
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) { | ||
|