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 = kmalloc(size, GFP_KERNEL);
384 if (!buf) {
385 pr_err("lock_torture_stats_print: Out of memory, need: %d",
386 size);
387 return;
388 }
389
390 __torture_print_stats(buf, lrsa, false);
391 pr_alert("%s", buf);
392 kfree(buf);
393 }
327} 394}
328 395
329/* 396/*
@@ -350,10 +417,10 @@ lock_torture_print_module_parms(struct lock_torture_ops *cur_ops,
350 const char *tag) 417 const char *tag)
351{ 418{
352 pr_alert("%s" TORTURE_FLAG 419 pr_alert("%s" TORTURE_FLAG
353 "--- %s%s: nwriters_stress=%d stat_interval=%d verbose=%d shuffle_interval=%d stutter=%d shutdown_secs=%d onoff_interval=%d onoff_holdoff=%d\n", 420 "--- %s%s: nwriters_stress=%d nreaders_stress=%d stat_interval=%d verbose=%d shuffle_interval=%d stutter=%d shutdown_secs=%d onoff_interval=%d onoff_holdoff=%d\n",
354 torture_type, tag, debug_lock ? " [debug]": "", 421 torture_type, tag, debug_lock ? " [debug]": "",
355 nrealwriters_stress, stat_interval, verbose, 422 nrealwriters_stress, nrealreaders_stress, stat_interval,
356 shuffle_interval, stutter, shutdown_secs, 423 verbose, shuffle_interval, stutter, shutdown_secs,
357 onoff_interval, onoff_holdoff); 424 onoff_interval, onoff_holdoff);
358} 425}
359 426
@@ -372,6 +439,14 @@ static void lock_torture_cleanup(void)
372 writer_tasks = NULL; 439 writer_tasks = NULL;
373 } 440 }
374 441
442 if (reader_tasks) {
443 for (i = 0; i < nrealreaders_stress; i++)
444 torture_stop_kthread(lock_torture_reader,
445 reader_tasks[i]);
446 kfree(reader_tasks);
447 reader_tasks = NULL;
448 }
449
375 torture_stop_kthread(lock_torture_stats, stats_task); 450 torture_stop_kthread(lock_torture_stats, stats_task);
376 lock_torture_stats_print(); /* -After- the stats thread is stopped! */ 451 lock_torture_stats_print(); /* -After- the stats thread is stopped! */
377 452
@@ -389,7 +464,7 @@ static void lock_torture_cleanup(void)
389 464
390static int __init lock_torture_init(void) 465static int __init lock_torture_init(void)
391{ 466{
392 int i; 467 int i, j;
393 int firsterr = 0; 468 int firsterr = 0;
394 static struct lock_torture_ops *torture_ops[] = { 469 static struct lock_torture_ops *torture_ops[] = {
395 &lock_busted_ops, &spin_lock_ops, &spin_lock_irq_ops, &mutex_lock_ops, 470 &lock_busted_ops, &spin_lock_ops, &spin_lock_irq_ops, &mutex_lock_ops,
@@ -430,7 +505,6 @@ static int __init lock_torture_init(void)
430 if (strncmp(torture_type, "spin", 4) == 0) 505 if (strncmp(torture_type, "spin", 4) == 0)
431 debug_lock = true; 506 debug_lock = true;
432#endif 507#endif
433 lock_torture_print_module_parms(cur_ops, "Start of test");
434 508
435 /* Initialize the statistics so that each run gets its own numbers. */ 509 /* Initialize the statistics so that each run gets its own numbers. */
436 510
@@ -446,8 +520,37 @@ static int __init lock_torture_init(void)
446 lwsa[i].n_lock_acquired = 0; 520 lwsa[i].n_lock_acquired = 0;
447 } 521 }
448 522
449 /* Start up the kthreads. */ 523 if (cur_ops->readlock) {
524 if (nreaders_stress >= 0)
525 nrealreaders_stress = nreaders_stress;
526 else {
527 /*
528 * By default distribute evenly the number of
529 * readers and writers. We still run the same number
530 * of threads as the writer-only locks default.
531 */
532 if (nwriters_stress < 0) /* user doesn't care */
533 nrealwriters_stress = num_online_cpus();
534 nrealreaders_stress = nrealwriters_stress;
535 }
536
537 lock_is_read_held = 0;
538 lrsa = kmalloc(sizeof(*lrsa) * nrealreaders_stress, GFP_KERNEL);
539 if (lrsa == NULL) {
540 VERBOSE_TOROUT_STRING("lrsa: Out of memory");
541 firsterr = -ENOMEM;
542 kfree(lwsa);
543 goto unwind;
544 }
450 545
546 for (i = 0; i < nrealreaders_stress; i++) {
547 lrsa[i].n_lock_fail = 0;
548 lrsa[i].n_lock_acquired = 0;
549 }
550 }
551 lock_torture_print_module_parms(cur_ops, "Start of test");
552
553 /* Prepare torture context. */
451 if (onoff_interval > 0) { 554 if (onoff_interval > 0) {
452 firsterr = torture_onoff_init(onoff_holdoff * HZ, 555 firsterr = torture_onoff_init(onoff_holdoff * HZ,
453 onoff_interval * HZ); 556 onoff_interval * HZ);
@@ -478,11 +581,44 @@ static int __init lock_torture_init(void)
478 firsterr = -ENOMEM; 581 firsterr = -ENOMEM;
479 goto unwind; 582 goto unwind;
480 } 583 }
481 for (i = 0; i < nrealwriters_stress; i++) { 584
585 if (cur_ops->readlock) {
586 reader_tasks = kzalloc(nrealreaders_stress * sizeof(reader_tasks[0]),
587 GFP_KERNEL);
588 if (reader_tasks == NULL) {
589 VERBOSE_TOROUT_ERRSTRING("reader_tasks: Out of memory");
590 firsterr = -ENOMEM;
591 goto unwind;
592 }
593 }
594
595 /*
596 * Create the kthreads and start torturing (oh, those poor little locks).
597 *
598 * TODO: Note that we interleave writers with readers, giving writers a
599 * slight advantage, by creating its kthread first. This can be modified
600 * for very specific needs, or even let the user choose the policy, if
601 * ever wanted.
602 */
603 for (i = 0, j = 0; i < nrealwriters_stress ||
604 j < nrealreaders_stress; i++, j++) {
605 if (i >= nrealwriters_stress)
606 goto create_reader;
607
608 /* Create writer. */
482 firsterr = torture_create_kthread(lock_torture_writer, &lwsa[i], 609 firsterr = torture_create_kthread(lock_torture_writer, &lwsa[i],
483 writer_tasks[i]); 610 writer_tasks[i]);
484 if (firsterr) 611 if (firsterr)
485 goto unwind; 612 goto unwind;
613
614 create_reader:
615 if (cur_ops->readlock == NULL || (j >= nrealreaders_stress))
616 continue;
617 /* Create reader. */
618 firsterr = torture_create_kthread(lock_torture_reader, &lrsa[j],
619 reader_tasks[j]);
620 if (firsterr)
621 goto unwind;
486 } 622 }
487 if (stat_interval > 0) { 623 if (stat_interval > 0) {
488 firsterr = torture_create_kthread(lock_torture_stats, NULL, 624 firsterr = torture_create_kthread(lock_torture_stats, NULL,