aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/locking
diff options
context:
space:
mode:
authorDavidlohr Bueso <dave@stgolabs.net>2014-09-12 00:40:41 -0400
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>2014-09-16 16:41:07 -0400
commit4f6332c1dce9c64ef6bf93842067250dd850e482 (patch)
treec1282b207d116fdb56acb3782e9e59e05c7214df /kernel/locking
parentd36a7a0d5e8b5bff1671723d733eb61621b0cee4 (diff)
locktorture: Add infrastructure for torturing read locks
Most of it is based on what we already have for writers. This allows readers to be very independent (and thus configurable), enabling future module parameters to control things such as rw distribution. Furthermore, readers have their own delaying function, allowing us to test different rw critical region latencies, and stress locking internals. Similarly, statistics, for now will only serve for the number of lock acquisitions -- as opposed to writers, readers have no failure detection. In addition, introduce a new nreaders_stress module parameter. The default number of readers will be the same number of writers threads. Writer threads are interleaved with readers. Documentation is updated, respectively. Signed-off-by: Davidlohr Bueso <dbueso@suse.de> Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Diffstat (limited to 'kernel/locking')
-rw-r--r--kernel/locking/locktorture.c176
1 files changed, 156 insertions, 20 deletions
diff --git a/kernel/locking/locktorture.c b/kernel/locking/locktorture.c
index 988267cc92c1..c1073d79e440 100644
--- a/kernel/locking/locktorture.c
+++ b/kernel/locking/locktorture.c
@@ -52,6 +52,8 @@ MODULE_AUTHOR("Paul E. McKenney <paulmck@us.ibm.com>");
52 52
53torture_param(int, nwriters_stress, -1, 53torture_param(int, nwriters_stress, -1,
54 "Number of write-locking stress-test threads"); 54 "Number of write-locking stress-test threads");
55torture_param(int, nreaders_stress, -1,
56 "Number of read-locking stress-test threads");
55torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs (s)"); 57torture_param(int, onoff_holdoff, 0, "Time after boot before CPU hotplugs (s)");
56torture_param(int, onoff_interval, 0, 58torture_param(int, onoff_interval, 0,
57 "Time between CPU hotplugs (s), 0=disable"); 59 "Time between CPU hotplugs (s), 0=disable");
@@ -74,15 +76,19 @@ static atomic_t n_lock_torture_errors;
74 76
75static struct task_struct *stats_task; 77static struct task_struct *stats_task;
76static struct task_struct **writer_tasks; 78static struct task_struct **writer_tasks;
79static struct task_struct **reader_tasks;
77 80
78static int nrealwriters_stress; 81static int nrealwriters_stress;
79static bool lock_is_write_held; 82static bool lock_is_write_held;
83static int nrealreaders_stress;
84static bool lock_is_read_held;
80 85
81struct lock_stress_stats { 86struct lock_stress_stats {
82 long n_lock_fail; 87 long n_lock_fail;
83 long n_lock_acquired; 88 long n_lock_acquired;
84}; 89};
85static struct lock_stress_stats *lwsa; /* writer statistics */ 90static struct lock_stress_stats *lwsa; /* writer statistics */
91static struct lock_stress_stats *lrsa; /* reader statistics */
86 92
87#if defined(MODULE) 93#if defined(MODULE)
88#define LOCKTORTURE_RUNNABLE_INIT 1 94#define LOCKTORTURE_RUNNABLE_INIT 1
@@ -104,6 +110,9 @@ struct lock_torture_ops {
104 int (*writelock)(void); 110 int (*writelock)(void);
105 void (*write_delay)(struct torture_random_state *trsp); 111 void (*write_delay)(struct torture_random_state *trsp);
106 void (*writeunlock)(void); 112 void (*writeunlock)(void);
113 int (*readlock)(void);
114 void (*read_delay)(struct torture_random_state *trsp);
115 void (*readunlock)(void);
107 unsigned long flags; 116 unsigned long flags;
108 const char *name; 117 const char *name;
109}; 118};
@@ -142,6 +151,9 @@ static struct lock_torture_ops lock_busted_ops = {
142 .writelock = torture_lock_busted_write_lock, 151 .writelock = torture_lock_busted_write_lock,
143 .write_delay = torture_lock_busted_write_delay, 152 .write_delay = torture_lock_busted_write_delay,
144 .writeunlock = torture_lock_busted_write_unlock, 153 .writeunlock = torture_lock_busted_write_unlock,
154 .readlock = NULL,
155 .read_delay = NULL,
156 .readunlock = NULL,
145 .name = "lock_busted" 157 .name = "lock_busted"
146}; 158};
147 159
@@ -182,6 +194,9 @@ static struct lock_torture_ops spin_lock_ops = {
182 .writelock = torture_spin_lock_write_lock, 194 .writelock = torture_spin_lock_write_lock,
183 .write_delay = torture_spin_lock_write_delay, 195 .write_delay = torture_spin_lock_write_delay,
184 .writeunlock = torture_spin_lock_write_unlock, 196 .writeunlock = torture_spin_lock_write_unlock,
197 .readlock = NULL,
198 .read_delay = NULL,
199 .readunlock = NULL,
185 .name = "spin_lock" 200 .name = "spin_lock"
186}; 201};
187 202
@@ -205,6 +220,9 @@ static struct lock_torture_ops spin_lock_irq_ops = {
205 .writelock = torture_spin_lock_write_lock_irq, 220 .writelock = torture_spin_lock_write_lock_irq,
206 .write_delay = torture_spin_lock_write_delay, 221 .write_delay = torture_spin_lock_write_delay,
207 .writeunlock = torture_lock_spin_write_unlock_irq, 222 .writeunlock = torture_lock_spin_write_unlock_irq,
223 .readlock = NULL,
224 .read_delay = NULL,
225 .readunlock = NULL,
208 .name = "spin_lock_irq" 226 .name = "spin_lock_irq"
209}; 227};
210 228
@@ -241,6 +259,9 @@ static struct lock_torture_ops mutex_lock_ops = {
241 .writelock = torture_mutex_lock, 259 .writelock = torture_mutex_lock,
242 .write_delay = torture_mutex_delay, 260 .write_delay = torture_mutex_delay,
243 .writeunlock = torture_mutex_unlock, 261 .writeunlock = torture_mutex_unlock,
262 .readlock = NULL,
263 .read_delay = NULL,
264 .readunlock = NULL,
244 .name = "mutex_lock" 265 .name = "mutex_lock"
245}; 266};
246 267
@@ -274,28 +295,57 @@ static int lock_torture_writer(void *arg)
274} 295}
275 296
276/* 297/*
298 * Lock torture reader kthread. Repeatedly acquires and releases
299 * the reader lock.
300 */
301static int lock_torture_reader(void *arg)
302{
303 struct lock_stress_stats *lrsp = arg;
304 static DEFINE_TORTURE_RANDOM(rand);
305
306 VERBOSE_TOROUT_STRING("lock_torture_reader task started");
307 set_user_nice(current, MAX_NICE);
308
309 do {
310 if ((torture_random(&rand) & 0xfffff) == 0)
311 schedule_timeout_uninterruptible(1);
312 cur_ops->readlock();
313 lock_is_read_held = 1;
314 lrsp->n_lock_acquired++;
315 cur_ops->read_delay(&rand);
316 lock_is_read_held = 0;
317 cur_ops->readunlock();
318 stutter_wait("lock_torture_reader");
319 } while (!torture_must_stop());
320 torture_kthread_stopping("lock_torture_reader");
321 return 0;
322}
323
324/*
277 * Create an lock-torture-statistics message in the specified buffer. 325 * Create an lock-torture-statistics message in the specified buffer.
278 */ 326 */
279static void lock_torture_printk(char *page) 327static void __torture_print_stats(char *page,
328 struct lock_stress_stats *statp, bool write)
280{ 329{
281 bool fail = 0; 330 bool fail = 0;
282 int i; 331 int i, n_stress;
283 long max = 0; 332 long max = 0;
284 long min = lwsa[0].n_lock_acquired; 333 long min = statp[0].n_lock_acquired;
285 long long sum = 0; 334 long long sum = 0;
286 335
287 for (i = 0; i < nrealwriters_stress; i++) { 336 n_stress = write ? nrealwriters_stress : nrealreaders_stress;
288 if (lwsa[i].n_lock_fail) 337 for (i = 0; i < n_stress; i++) {
338 if (statp[i].n_lock_fail)
289 fail = true; 339 fail = true;
290 sum += lwsa[i].n_lock_acquired; 340 sum += statp[i].n_lock_acquired;
291 if (max < lwsa[i].n_lock_fail) 341 if (max < statp[i].n_lock_fail)
292 max = lwsa[i].n_lock_fail; 342 max = statp[i].n_lock_fail;
293 if (min > lwsa[i].n_lock_fail) 343 if (min > statp[i].n_lock_fail)
294 min = lwsa[i].n_lock_fail; 344 min = statp[i].n_lock_fail;
295 } 345 }
296 page += sprintf(page, "%s%s ", torture_type, TORTURE_FLAG);
297 page += sprintf(page, 346 page += sprintf(page,
298 "Writes: Total: %lld Max/Min: %ld/%ld %s Fail: %d %s\n", 347 "%s: Total: %lld Max/Min: %ld/%ld %s Fail: %d %s\n",
348 write ? "Writes" : "Reads ",
299 sum, max, min, max / 2 > min ? "???" : "", 349 sum, max, min, max / 2 > min ? "???" : "",
300 fail, fail ? "!!!" : ""); 350 fail, fail ? "!!!" : "");
301 if (fail) 351 if (fail)
@@ -315,15 +365,32 @@ static void lock_torture_stats_print(void)
315 int size = nrealwriters_stress * 200 + 8192; 365 int size = nrealwriters_stress * 200 + 8192;
316 char *buf; 366 char *buf;
317 367
368 if (cur_ops->readlock)
369 size += nrealreaders_stress * 200 + 8192;
370
318 buf = kmalloc(size, GFP_KERNEL); 371 buf = kmalloc(size, GFP_KERNEL);
319 if (!buf) { 372 if (!buf) {
320 pr_err("lock_torture_stats_print: Out of memory, need: %d", 373 pr_err("lock_torture_stats_print: Out of memory, need: %d",
321 size); 374 size);
322 return; 375 return;
323 } 376 }
324 lock_torture_printk(buf); 377
378 __torture_print_stats(buf, lwsa, true);
325 pr_alert("%s", buf); 379 pr_alert("%s", buf);
326 kfree(buf); 380 kfree(buf);
381
382 if (cur_ops->readlock) {
383 buf = kmall