diff options
| author | Steve French <sfrench@us.ibm.com> | 2006-01-12 17:47:08 -0500 |
|---|---|---|
| committer | Steve French <sfrench@us.ibm.com> | 2006-01-12 17:47:08 -0500 |
| commit | 94bc2be31a01a3055ec94176e595dfe208e92d3b (patch) | |
| tree | ebfbe81c6718a6390bfa1b99c6d228237d818576 /kernel/rcutorture.c | |
| parent | c32a0b689cb9cc160cfcd19735bbf50bb70c6ef4 (diff) | |
| parent | 58cba4650a7a414eabd2b40cc9d8e45fcdf192d9 (diff) | |
Merge with /pub/scm/linux/kernel/git/torvalds/linux-2.6.git
Signed-off-by: Steve French <sfrench@us.ibm.com>
Diffstat (limited to 'kernel/rcutorture.c')
| -rw-r--r-- | kernel/rcutorture.c | 99 |
1 files changed, 92 insertions, 7 deletions
diff --git a/kernel/rcutorture.c b/kernel/rcutorture.c index 49fbbeff201c..773219907dd8 100644 --- a/kernel/rcutorture.c +++ b/kernel/rcutorture.c | |||
| @@ -39,7 +39,6 @@ | |||
| 39 | #include <linux/moduleparam.h> | 39 | #include <linux/moduleparam.h> |
| 40 | #include <linux/percpu.h> | 40 | #include <linux/percpu.h> |
| 41 | #include <linux/notifier.h> | 41 | #include <linux/notifier.h> |
| 42 | #include <linux/rcuref.h> | ||
| 43 | #include <linux/cpu.h> | 42 | #include <linux/cpu.h> |
| 44 | #include <linux/random.h> | 43 | #include <linux/random.h> |
| 45 | #include <linux/delay.h> | 44 | #include <linux/delay.h> |
| @@ -49,9 +48,11 @@ | |||
| 49 | MODULE_LICENSE("GPL"); | 48 | MODULE_LICENSE("GPL"); |
| 50 | 49 | ||
| 51 | static int nreaders = -1; /* # reader threads, defaults to 4*ncpus */ | 50 | static int nreaders = -1; /* # reader threads, defaults to 4*ncpus */ |
| 52 | static int stat_interval = 0; /* Interval between stats, in seconds. */ | 51 | static int stat_interval; /* Interval between stats, in seconds. */ |
| 53 | /* Defaults to "only at end of test". */ | 52 | /* Defaults to "only at end of test". */ |
| 54 | static int verbose = 0; /* Print more debug info. */ | 53 | static int verbose; /* Print more debug info. */ |
| 54 | static int test_no_idle_hz; /* Test RCU's support for tickless idle CPUs. */ | ||
| 55 | static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/ | ||
| 55 | 56 | ||
| 56 | MODULE_PARM(nreaders, "i"); | 57 | MODULE_PARM(nreaders, "i"); |
| 57 | MODULE_PARM_DESC(nreaders, "Number of RCU reader threads"); | 58 | MODULE_PARM_DESC(nreaders, "Number of RCU reader threads"); |
| @@ -59,6 +60,10 @@ MODULE_PARM(stat_interval, "i"); | |||
| 59 | MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s"); | 60 | MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s"); |
| 60 | MODULE_PARM(verbose, "i"); | 61 | MODULE_PARM(verbose, "i"); |
| 61 | MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s"); | 62 | MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s"); |
| 63 | MODULE_PARM(test_no_idle_hz, "i"); | ||
| 64 | MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs"); | ||
| 65 | MODULE_PARM(shuffle_interval, "i"); | ||
| 66 | MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles"); | ||
| 62 | #define TORTURE_FLAG "rcutorture: " | 67 | #define TORTURE_FLAG "rcutorture: " |
| 63 | #define PRINTK_STRING(s) \ | 68 | #define PRINTK_STRING(s) \ |
| 64 | do { printk(KERN_ALERT TORTURE_FLAG s "\n"); } while (0) | 69 | do { printk(KERN_ALERT TORTURE_FLAG s "\n"); } while (0) |
| @@ -73,6 +78,7 @@ static int nrealreaders; | |||
| 73 | static struct task_struct *writer_task; | 78 | static struct task_struct *writer_task; |
| 74 | static struct task_struct **reader_tasks; | 79 | static struct task_struct **reader_tasks; |
| 75 | static struct task_struct *stats_task; | 80 | static struct task_struct *stats_task; |
| 81 | static struct task_struct *shuffler_task; | ||
| 76 | 82 | ||
| 77 | #define RCU_TORTURE_PIPE_LEN 10 | 83 | #define RCU_TORTURE_PIPE_LEN 10 |
| 78 | 84 | ||
| @@ -103,7 +109,7 @@ atomic_t n_rcu_torture_error; | |||
| 103 | /* | 109 | /* |
| 104 | * Allocate an element from the rcu_tortures pool. | 110 | * Allocate an element from the rcu_tortures pool. |
| 105 | */ | 111 | */ |
| 106 | struct rcu_torture * | 112 | static struct rcu_torture * |
| 107 | rcu_torture_alloc(void) | 113 | rcu_torture_alloc(void) |
| 108 | { | 114 | { |
| 109 | struct list_head *p; | 115 | struct list_head *p; |
| @@ -376,12 +382,77 @@ rcu_torture_stats(void *arg) | |||
| 376 | return 0; | 382 | return 0; |
| 377 | } | 383 | } |
| 378 | 384 | ||
| 385 | static int rcu_idle_cpu; /* Force all torture tasks off this CPU */ | ||
| 386 | |||
| 387 | /* Shuffle tasks such that we allow @rcu_idle_cpu to become idle. A special case | ||
| 388 | * is when @rcu_idle_cpu = -1, when we allow the tasks to run on all CPUs. | ||
| 389 | */ | ||
| 390 | void rcu_torture_shuffle_tasks(void) | ||
| 391 | { | ||
| 392 | cpumask_t tmp_mask = CPU_MASK_ALL; | ||
| 393 | int i; | ||
| 394 | |||
| 395 | lock_cpu_hotplug(); | ||
| 396 | |||
| 397 | /* No point in shuffling if there is only one online CPU (ex: UP) */ | ||
| 398 | if (num_online_cpus() == 1) { | ||
| 399 | unlock_cpu_hotplug(); | ||
| 400 | return; | ||
| 401 | } | ||
| 402 | |||
| 403 | if (rcu_idle_cpu != -1) | ||
| 404 | cpu_clear(rcu_idle_cpu, tmp_mask); | ||
| 405 | |||
| 406 | set_cpus_allowed(current, tmp_mask); | ||
| 407 | |||
| 408 | if (reader_tasks != NULL) { | ||
| 409 | for (i = 0; i < nrealreaders; i++) | ||
| 410 | if (reader_tasks[i]) | ||
| 411 | set_cpus_allowed(reader_tasks[i], tmp_mask); | ||
| 412 | } | ||
| 413 | |||
| 414 | if (writer_task) | ||
| 415 | set_cpus_allowed(writer_task, tmp_mask); | ||
| 416 | |||
| 417 | if (stats_task) | ||
| 418 | set_cpus_allowed(stats_task, tmp_mask); | ||
| 419 | |||
| 420 | if (rcu_idle_cpu == -1) | ||
| 421 | rcu_idle_cpu = num_online_cpus() - 1; | ||
| 422 | else | ||
| 423 | rcu_idle_cpu--; | ||
| 424 | |||
| 425 | unlock_cpu_hotplug(); | ||
| 426 | } | ||
| 427 | |||
| 428 | /* Shuffle tasks across CPUs, with the intent of allowing each CPU in the | ||
| 429 | * system to become idle at a time and cut off its timer ticks. This is meant | ||
| 430 | * to test the support for such tickless idle CPU in RCU. | ||
| 431 | */ | ||
| 432 | static int | ||
| 433 | rcu_torture_shuffle(void *arg) | ||
| 434 | { | ||
| 435 | VERBOSE_PRINTK_STRING("rcu_torture_shuffle task started"); | ||
| 436 | do { | ||
| 437 | schedule_timeout_interruptible(shuffle_interval * HZ); | ||
| 438 | rcu_torture_shuffle_tasks(); | ||
| 439 | } while (!kthread_should_stop()); | ||
| 440 | VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping"); | ||
| 441 | return 0; | ||
| 442 | } | ||
| 443 | |||
| 379 | static void | 444 | static void |
| 380 | rcu_torture_cleanup(void) | 445 | rcu_torture_cleanup(void) |
| 381 | { | 446 | { |
| 382 | int i; | 447 | int i; |
| 383 | 448 | ||
| 384 | fullstop = 1; | 449 | fullstop = 1; |
| 450 | if (shuffler_task != NULL) { | ||
| 451 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task"); | ||
| 452 | kthread_stop(shuffler_task); | ||
| 453 | } | ||
| 454 | shuffler_task = NULL; | ||
| 455 | |||
| 385 | if (writer_task != NULL) { | 456 | if (writer_task != NULL) { |
| 386 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_writer task"); | 457 | VERBOSE_PRINTK_STRING("Stopping rcu_torture_writer task"); |
| 387 | kthread_stop(writer_task); | 458 | kthread_stop(writer_task); |
| @@ -430,9 +501,11 @@ rcu_torture_init(void) | |||
| 430 | nrealreaders = nreaders; | 501 | nrealreaders = nreaders; |
| 431 | else | 502 | else |
| 432 | nrealreaders = 2 * num_online_cpus(); | 503 | nrealreaders = 2 * num_online_cpus(); |
| 433 | printk(KERN_ALERT TORTURE_FLAG | 504 | printk(KERN_ALERT TORTURE_FLAG "--- Start of test: nreaders=%d " |
| 434 | "--- Start of test: nreaders=%d stat_interval=%d verbose=%d\n", | 505 | "stat_interval=%d verbose=%d test_no_idle_hz=%d " |
| 435 | nrealreaders, stat_interval, verbose); | 506 | "shuffle_interval = %d\n", |
| 507 | nrealreaders, stat_interval, verbose, test_no_idle_hz, | ||
| 508 | shuffle_interval); | ||
| 436 | fullstop = 0; | 509 | fullstop = 0; |
| 437 | 510 | ||
| 438 | /* Set up the freelist. */ | 511 | /* Set up the freelist. */ |
| @@ -502,6 +575,18 @@ rcu_torture_init(void) | |||
| 502 | goto unwind; | 575 | goto unwind; |
| 503 | } | 576 | } |
| 504 | } | 577 | } |
| 578 | if (test_no_idle_hz) { | ||
| 579 | rcu_idle_cpu = num_online_cpus() - 1; | ||
| 580 | /* Create the shuffler thread */ | ||
| 581 | shuffler_task = kthread_run(rcu_torture_shuffle, NULL, | ||
| 582 | "rcu_torture_shuffle"); | ||
| 583 | if (IS_ERR(shuffler_task)) { | ||
| 584 | firsterr = PTR_ERR(shuffler_task); | ||
| 585 | VERBOSE_PRINTK_ERRSTRING("Failed to create shuffler"); | ||
| 586 | shuffler_task = NULL; | ||
| 587 | goto unwind; | ||
| 588 | } | ||
| 589 | } | ||
| 505 | return 0; | 590 | return 0; |
| 506 | 591 | ||
| 507 | unwind: | 592 | unwind: |
