2005-12-05 11:03:58

by Srivatsa Vaddagiri

[permalink] [raw]
Subject: [PATCH] Extend RCU torture module to test tickless idle CPU

This patch forces RCU torture threads off various CPUs in the system
allowing them to become idle and go tickless. Meant to test support for
such tickless idle CPU in RCU.

Signed-off-by : Srivatsa Vaddagiri <[email protected]>

---

linux-2.6.15-rc5-mm1-root/kernel/rcutorture.c | 89 +++++++++++++++++++++++++-
1 files changed, 87 insertions(+), 2 deletions(-)

diff -puN kernel/rcutorture.c~rcutorture kernel/rcutorture.c
--- linux-2.6.15-rc5-mm1/kernel/rcutorture.c~rcutorture 2005-12-05 15:33:34.000000000 +0530
+++ linux-2.6.15-rc5-mm1-root/kernel/rcutorture.c 2005-12-05 15:33:42.000000000 +0530
@@ -51,6 +51,8 @@ static int nreaders = -1; /* # reader th
static int stat_interval = 0; /* Interval between stats, in seconds. */
/* Defaults to "only at end of test". */
static int verbose = 0; /* Print more debug info. */
+static int test_no_idle_hz = 0; /* Test RCU's support for tickless idle CPUs. */
+static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/

MODULE_PARM(nreaders, "i");
MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
@@ -58,6 +60,10 @@ MODULE_PARM(stat_interval, "i");
MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
MODULE_PARM(verbose, "i");
MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
+MODULE_PARM(test_no_idle_hz, "i");
+MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
+MODULE_PARM(shuffle_interval, "i");
+MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
#define TORTURE_FLAG "rcutorture: "
#define PRINTK_STRING(s) \
do { printk(KERN_ALERT TORTURE_FLAG s "\n"); } while (0)
@@ -72,6 +78,7 @@ static int nrealreaders;
static struct task_struct *writer_task;
static struct task_struct **reader_tasks;
static struct task_struct *stats_task;
+static struct task_struct *shuffler_task;

#define RCU_TORTURE_PIPE_LEN 10

@@ -375,12 +382,77 @@ rcu_torture_stats(void *arg)
return 0;
}

+int rcu_idle_cpu; /* Force all torture tasks off this CPU */
+
+/* Shuffle tasks such that we allow @rcu_idle_cpu to become idle. A special case
+ * is when @rcu_idle_cpu = -1, when we allow the tasks to run on all CPUs.
+ */
+void rcu_torture_shuffle_tasks(void)
+{
+ cpumask_t tmp_mask = CPU_MASK_ALL;
+ int i;
+
+ lock_cpu_hotplug();
+
+ /* No point in shuffling if there is only one online CPU (ex: UP) */
+ if (num_online_cpus() == 1) {
+ unlock_cpu_hotplug();
+ return;
+ }
+
+ if (rcu_idle_cpu != -1)
+ cpu_clear(rcu_idle_cpu, tmp_mask);
+
+ set_cpus_allowed(current, tmp_mask);
+
+ if (reader_tasks != NULL) {
+ for (i = 0; i < nrealreaders; i++)
+ if (reader_tasks[i])
+ set_cpus_allowed(reader_tasks[i], tmp_mask);
+ }
+
+ if (writer_task)
+ set_cpus_allowed(writer_task, tmp_mask);
+
+ if (stats_task)
+ set_cpus_allowed(stats_task, tmp_mask);
+
+ if (rcu_idle_cpu == -1)
+ rcu_idle_cpu = num_online_cpus() - 1;
+ else
+ rcu_idle_cpu--;
+
+ unlock_cpu_hotplug();
+}
+
+/* Shuffle tasks across CPUs, with the intent of allowing each CPU in the
+ * system to become idle at a time and cut off its timer ticks. This is meant
+ * to test the support for such tickless idle CPU in RCU.
+ */
+static int
+rcu_torture_shuffle(void *arg)
+{
+ VERBOSE_PRINTK_STRING("rcu_torture_shuffle task started");
+ do {
+ schedule_timeout_interruptible(shuffle_interval * HZ);
+ rcu_torture_shuffle_tasks();
+ } while (!kthread_should_stop());
+ VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping");
+ return 0;
+}
+
static void
rcu_torture_cleanup(void)
{
int i;

fullstop = 1;
+ if (shuffler_task != NULL) {
+ VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task");
+ kthread_stop(shuffler_task);
+ }
+ shuffler_task = NULL;
+
if (writer_task != NULL) {
VERBOSE_PRINTK_STRING("Stopping rcu_torture_writer task");
kthread_stop(writer_task);
@@ -430,8 +502,9 @@ rcu_torture_init(void)
else
nrealreaders = 2 * num_online_cpus();
printk(KERN_ALERT TORTURE_FLAG
- "--- Start of test: nreaders=%d stat_interval=%d verbose=%d\n",
- nrealreaders, stat_interval, verbose);
+ "--- Start of test: nreaders=%d stat_interval=%d verbose=%d test_no_idle_hz=%d shuffle_interval = %d\n",
+ nrealreaders, stat_interval, verbose, test_no_idle_hz,
+ shuffle_interval);
fullstop = 0;

/* Set up the freelist. */
@@ -501,6 +574,18 @@ rcu_torture_init(void)
goto unwind;
}
}
+ if (test_no_idle_hz) {
+ rcu_idle_cpu = num_online_cpus() - 1;
+ /* Create the shuffler thread */
+ shuffler_task = kthread_run(rcu_torture_shuffle, NULL,
+ "rcu_torture_shuffle");
+ if (IS_ERR(shuffler_task)) {
+ firsterr = PTR_ERR(shuffler_task);
+ VERBOSE_PRINTK_ERRSTRING("Failed to create shuffler");
+ shuffler_task = NULL;
+ goto unwind;
+ }
+ }
return 0;

unwind:

_
--


Thanks and Regards,
Srivatsa Vaddagiri,
Linux Technology Center,
IBM Software Labs,
Bangalore, INDIA - 560017


2005-12-05 21:22:36

by Pavel Machek

[permalink] [raw]
Subject: Re: [PATCH] Extend RCU torture module to test tickless idle CPU

Hi!

> This patch forces RCU torture threads off various CPUs in the system
> allowing them to become idle and go tickless. Meant to test support for
> such tickless idle CPU in RCU.
>
> Signed-off-by : Srivatsa Vaddagiri <[email protected]>
>
> ---
>
> linux-2.6.15-rc5-mm1-root/kernel/rcutorture.c | 89 +++++++++++++++++++++++++-
> 1 files changed, 87 insertions(+), 2 deletions(-)
>
> diff -puN kernel/rcutorture.c~rcutorture kernel/rcutorture.c
> --- linux-2.6.15-rc5-mm1/kernel/rcutorture.c~rcutorture 2005-12-05 15:33:34.000000000 +0530
> +++ linux-2.6.15-rc5-mm1-root/kernel/rcutorture.c 2005-12-05 15:33:42.000000000 +0530
> @@ -51,6 +51,8 @@ static int nreaders = -1; /* # reader th
> static int stat_interval = 0; /* Interval between stats, in seconds. */
> /* Defaults to "only at end of test". */
> static int verbose = 0; /* Print more debug info. */
> +static int test_no_idle_hz = 0; /* Test RCU's support for tickless idle CPUs. */

0 initializers are not needed. Also comment formatting is
"interesting".

> @@ -375,12 +382,77 @@ rcu_torture_stats(void *arg)
> return 0;
> }
>
> +int rcu_idle_cpu; /* Force all torture tasks off this CPU */

Missing static?

> +/* Shuffle tasks across CPUs, with the intent of allowing each CPU in the
> + * system to become idle at a time and cut off its timer ticks. This is meant
> + * to test the support for such tickless idle CPU in RCU.
> + */
> +static int
> +rcu_torture_shuffle(void *arg)
> +{
> + VERBOSE_PRINTK_STRING("rcu_torture_shuffle task started");

Do you really need to append _STRING here?

Pavel
--
Thanks, Sharp!

2006-01-11 18:12:32

by Paul E. McKenney

[permalink] [raw]
Subject: Re: [PATCH] Extend RCU torture module to test tickless idle CPU

On Mon, Dec 05, 2005 at 04:35:27PM +0530, Srivatsa Vaddagiri wrote:
> This patch forces RCU torture threads off various CPUs in the system
> allowing them to become idle and go tickless. Meant to test support for
> such tickless idle CPU in RCU.

Good addition, works on 2.6.15 on x86 and ppc64.

Thanx, Paul

Acked-by: Paul E. McKenney <[email protected]>
> Signed-off-by : Srivatsa Vaddagiri <[email protected]>
>
> ---
>
> linux-2.6.15-rc5-mm1-root/kernel/rcutorture.c | 89 +++++++++++++++++++++++++-
> 1 files changed, 87 insertions(+), 2 deletions(-)
>
> diff -puN kernel/rcutorture.c~rcutorture kernel/rcutorture.c
> --- linux-2.6.15-rc5-mm1/kernel/rcutorture.c~rcutorture 2005-12-05 15:33:34.000000000 +0530
> +++ linux-2.6.15-rc5-mm1-root/kernel/rcutorture.c 2005-12-05 15:33:42.000000000 +0530
> @@ -51,6 +51,8 @@ static int nreaders = -1; /* # reader th
> static int stat_interval = 0; /* Interval between stats, in seconds. */
> /* Defaults to "only at end of test". */
> static int verbose = 0; /* Print more debug info. */
> +static int test_no_idle_hz = 0; /* Test RCU's support for tickless idle CPUs. */
> +static int shuffle_interval = 5; /* Interval between shuffles (in sec)*/
>
> MODULE_PARM(nreaders, "i");
> MODULE_PARM_DESC(nreaders, "Number of RCU reader threads");
> @@ -58,6 +60,10 @@ MODULE_PARM(stat_interval, "i");
> MODULE_PARM_DESC(stat_interval, "Number of seconds between stats printk()s");
> MODULE_PARM(verbose, "i");
> MODULE_PARM_DESC(verbose, "Enable verbose debugging printk()s");
> +MODULE_PARM(test_no_idle_hz, "i");
> +MODULE_PARM_DESC(test_no_idle_hz, "Test support for tickless idle CPUs");
> +MODULE_PARM(shuffle_interval, "i");
> +MODULE_PARM_DESC(shuffle_interval, "Number of seconds between shuffles");
> #define TORTURE_FLAG "rcutorture: "
> #define PRINTK_STRING(s) \
> do { printk(KERN_ALERT TORTURE_FLAG s "\n"); } while (0)
> @@ -72,6 +78,7 @@ static int nrealreaders;
> static struct task_struct *writer_task;
> static struct task_struct **reader_tasks;
> static struct task_struct *stats_task;
> +static struct task_struct *shuffler_task;
>
> #define RCU_TORTURE_PIPE_LEN 10
>
> @@ -375,12 +382,77 @@ rcu_torture_stats(void *arg)
> return 0;
> }
>
> +int rcu_idle_cpu; /* Force all torture tasks off this CPU */
> +
> +/* Shuffle tasks such that we allow @rcu_idle_cpu to become idle. A special case
> + * is when @rcu_idle_cpu = -1, when we allow the tasks to run on all CPUs.
> + */
> +void rcu_torture_shuffle_tasks(void)
> +{
> + cpumask_t tmp_mask = CPU_MASK_ALL;
> + int i;
> +
> + lock_cpu_hotplug();
> +
> + /* No point in shuffling if there is only one online CPU (ex: UP) */
> + if (num_online_cpus() == 1) {
> + unlock_cpu_hotplug();
> + return;
> + }
> +
> + if (rcu_idle_cpu != -1)
> + cpu_clear(rcu_idle_cpu, tmp_mask);
> +
> + set_cpus_allowed(current, tmp_mask);
> +
> + if (reader_tasks != NULL) {
> + for (i = 0; i < nrealreaders; i++)
> + if (reader_tasks[i])
> + set_cpus_allowed(reader_tasks[i], tmp_mask);
> + }
> +
> + if (writer_task)
> + set_cpus_allowed(writer_task, tmp_mask);
> +
> + if (stats_task)
> + set_cpus_allowed(stats_task, tmp_mask);
> +
> + if (rcu_idle_cpu == -1)
> + rcu_idle_cpu = num_online_cpus() - 1;
> + else
> + rcu_idle_cpu--;
> +
> + unlock_cpu_hotplug();
> +}
> +
> +/* Shuffle tasks across CPUs, with the intent of allowing each CPU in the
> + * system to become idle at a time and cut off its timer ticks. This is meant
> + * to test the support for such tickless idle CPU in RCU.
> + */
> +static int
> +rcu_torture_shuffle(void *arg)
> +{
> + VERBOSE_PRINTK_STRING("rcu_torture_shuffle task started");
> + do {
> + schedule_timeout_interruptible(shuffle_interval * HZ);
> + rcu_torture_shuffle_tasks();
> + } while (!kthread_should_stop());
> + VERBOSE_PRINTK_STRING("rcu_torture_shuffle task stopping");
> + return 0;
> +}
> +
> static void
> rcu_torture_cleanup(void)
> {
> int i;
>
> fullstop = 1;
> + if (shuffler_task != NULL) {
> + VERBOSE_PRINTK_STRING("Stopping rcu_torture_shuffle task");
> + kthread_stop(shuffler_task);
> + }
> + shuffler_task = NULL;
> +
> if (writer_task != NULL) {
> VERBOSE_PRINTK_STRING("Stopping rcu_torture_writer task");
> kthread_stop(writer_task);
> @@ -430,8 +502,9 @@ rcu_torture_init(void)
> else
> nrealreaders = 2 * num_online_cpus();
> printk(KERN_ALERT TORTURE_FLAG
> - "--- Start of test: nreaders=%d stat_interval=%d verbose=%d\n",
> - nrealreaders, stat_interval, verbose);
> + "--- Start of test: nreaders=%d stat_interval=%d verbose=%d test_no_idle_hz=%d shuffle_interval = %d\n",
> + nrealreaders, stat_interval, verbose, test_no_idle_hz,
> + shuffle_interval);
> fullstop = 0;
>
> /* Set up the freelist. */
> @@ -501,6 +574,18 @@ rcu_torture_init(void)
> goto unwind;
> }
> }
> + if (test_no_idle_hz) {
> + rcu_idle_cpu = num_online_cpus() - 1;
> + /* Create the shuffler thread */
> + shuffler_task = kthread_run(rcu_torture_shuffle, NULL,
> + "rcu_torture_shuffle");
> + if (IS_ERR(shuffler_task)) {
> + firsterr = PTR_ERR(shuffler_task);
> + VERBOSE_PRINTK_ERRSTRING("Failed to create shuffler");
> + shuffler_task = NULL;
> + goto unwind;
> + }
> + }
> return 0;
>
> unwind:
>
> _
> --
>
>
> Thanks and Regards,
> Srivatsa Vaddagiri,
> Linux Technology Center,
> IBM Software Labs,
> Bangalore, INDIA - 560017
>