Skip to contentSkip to conversation

Waketorture, not for inclusion

RFC PATCH New Paul E. McKenney 1 participant 9 messages Jun 15, 2016

Subsystems (4)
lore
Share & tools
lore
#0 lore raw

cover Waketorture, not for inclusion

Hello!

And for your amusement, this series provides a waketorture module. It is intended to increase the probability of a heisenbug or three I have been chasing for longer than I care to admit. Should it someday actually significantly increase that probability, I might consider submitting it for acceptance. In the meantime, for your amusement:

1. Add a wakeup-torture module.

2. Update scripting to accommodate waketorture.

3. Don't kick kthreads unless grace period or request.

4. Add utilization measurement.

5. Add hrtimer support for fine-grained event scheduling.

6. Make waketorture always hotplug the same CPU.

7. Make waketorture kill test if no hotpluggable CPUs.

8. Affinity waiter tasks away from hotpluggable CPU.

Thanx, Paul

------------------------------------------------------------------------

 kernel/rcu/Makefile                                              |    3 
 kernel/rcu/tree.c                                                |    3 
 kernel/rcu/waketorture.c                                         |  567 +++++++++-
 lib/Kconfig.debug                                                |   18 
 tools/testing/selftests/rcutorture/bin/kvm-recheck-wake.sh       |   39 
 tools/testing/selftests/rcutorture/bin/kvm-recheck.sh            |    2 
 tools/testing/selftests/rcutorture/bin/kvm.sh                    |    2 
 tools/testing/selftests/rcutorture/configs/wake/CFLIST           |    1 
 tools/testing/selftests/rcutorture/configs/wake/CFcommon         |    2 
 tools/testing/selftests/rcutorture/configs/wake/SH               |   19 
 tools/testing/selftests/rcutorture/configs/wake/SH.boot          |    1 
 tools/testing/selftests/rcutorture/configs/wake/STI              |   19 
 tools/testing/selftests/rcutorture/configs/wake/STI.boot         |    1 
 tools/testing/selftests/rcutorture/configs/wake/ver_functions.sh |   43 
 14 files changed, 701 insertions(+), 19 deletions(-)
#1 lore raw

PATCH 1/8 waketorture: Add a wakeup-torture module

This commit adds a wakeup-torture module to assist tracking down an elusive lost-wakeup problem.

---
 kernel/rcu/Makefile      |   3 +-
 kernel/rcu/waketorture.c | 371 +++++++++++++++++++++++++++++++++++++++++++++++
 lib/Kconfig.debug        |  17 +++
 3 files changed, 390 insertions(+), 1 deletion(-)
 create mode 100644 kernel/rcu/waketorture.c
kernel/rcu/Makefile +2 -1
index 18dfc485225c..42cd319920b1 100644
@@ -4,9 +4,10 @@ KCOV_INSTRUMENT := n
 
 obj-y += update.o sync.o
 obj-$(CONFIG_SRCU) += srcu.o
-obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
 obj-$(CONFIG_RCU_PERF_TEST) += rcuperf.o
+obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
 obj-$(CONFIG_TREE_RCU) += tree.o
 obj-$(CONFIG_PREEMPT_RCU) += tree.o
 obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o
 obj-$(CONFIG_TINY_RCU) += tiny.o
+obj-$(CONFIG_WAKE_TORTURE_TEST) += waketorture.o
kernel/rcu/waketorture.c new file +371 -0

371 lines not on this page · raw message

lib/Kconfig.debug +17 -0
index 805b7048a1bd..f0dcb4c0fe96 100644
@@ -1399,6 +1399,23 @@ config RCU_TORTURE_TEST_SLOW_CLEANUP_DELAY
 	  This option specifies the number of jiffies to wait between
 	  each rcu_node structure cleanup operation.
 
+config WAKE_TORTURE_TEST
+	tristate "Torture test for wakeups and CPU hotplug"
+	depends on DEBUG_KERNEL
+	depends on 64BIT
+	select TORTURE_TEST
+	default n
+	help
+	  This option provides a kernel module that runs torture tests
+	  on wakeups from timed waits in the presence of CPU hotplug.
+	  The kernel module may be built after the fact on the running
+	  kernel to be tested, if desired.
+
+	  Say Y here if you want wakeup torture tests to be built into
+	  the kernel.
+	  Say M if you want the wakeup torture tests to build as a module.
+	  Say N if you are unsure.
+
 config RCU_CPU_STALL_TIMEOUT
 	int "RCU CPU stall timeout in seconds"
 	depends on RCU_STALL_COMMON
Signature · 1 line
2.5.2
#2 lore raw

PATCH 2/8 waketorture: Update scripting to accommodate waketorture

In reply to Paul E. McKenney

This commit adds the scripting changes to add support for the shiny new waketorture kernel module.

---
 .../selftests/rcutorture/bin/kvm-recheck-wake.sh   | 39 ++++++++++++++++++++
 .../selftests/rcutorture/bin/kvm-recheck.sh        |  2 +-
 tools/testing/selftests/rcutorture/bin/kvm.sh      |  2 +-
 .../selftests/rcutorture/configs/wake/CFLIST       |  1 +
 .../selftests/rcutorture/configs/wake/CFcommon     |  2 +
 .../testing/selftests/rcutorture/configs/wake/STI  | 19 ++++++++++
 .../selftests/rcutorture/configs/wake/STI.boot     |  1 +
 .../rcutorture/configs/wake/ver_functions.sh       | 43 ++++++++++++++++++++++
 8 files changed, 107 insertions(+), 2 deletions(-)
 create mode 100755 tools/testing/selftests/rcutorture/bin/kvm-recheck-wake.sh
 create mode 100644 tools/testing/selftests/rcutorture/configs/wake/CFLIST
 create mode 100644 tools/testing/selftests/rcutorture/configs/wake/CFcommon
 create mode 100644 tools/testing/selftests/rcutorture/configs/wake/STI
 create mode 100644 tools/testing/selftests/rcutorture/configs/wake/STI.boot
 create mode 100644 tools/testing/selftests/rcutorture/configs/wake/ver_functions.sh
tools/testing/selftests/rcutorture/bin/kvm-recheck-wake.sh new file +39 -0
new file mode 100755
index 000000000000..fc9ee1920acb
@@ -0,0 +1,39 @@
+#!/bin/bash
+#
+# Analyze a given results directory for waketorture diagnostics.
+#
+# Usage: kvm-recheck-wake resdir
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, you can access it online at
+# http://www.gnu.org/licenses/gpl-2.0.html.
+#
+# Copyright (C) IBM Corporation, 2016
+#
+# Authors: Paul E. McKenney <[email protected]>
+
+i="$1"
+if test -d $i
+then
+	:
+else
+	echo Unreadable results directory: $i
+	exit 1
+fi
+PATH=`pwd`/tools/testing/selftests/rcutorture/bin:$PATH; export PATH
+. tools/testing/selftests/rcutorture/bin/functions.sh
+
+configfile=`echo $i | sed -e 's/^.*\///'`
+
+sed -e 's/^\[[^]]*]//' < $i/console.log | grep -e -torture |
+	grep "Tardy kthreads" | tail -1
tools/testing/selftests/rcutorture/bin/kvm-recheck.sh +1 -1
index f659346d3358..060c1eec73f4 100755
@@ -48,7 +48,7 @@ do
 				cat $i/Make.oldconfig.err
 			fi
 			parse-build.sh $i/Make.out $configfile
-			if test "$TORTURE_SUITE" != rcuperf
+			if test "$TORTURE_SUITE" != rcuperf -a "$TORTURE_SUITE" != wake
 			then
 				parse-torture.sh $i/console.log $configfile
 			fi
tools/testing/selftests/rcutorture/bin/kvm.sh +1 -1
index 0aed965f0062..0109ddf7b666 100755
@@ -163,7 +163,7 @@ do
 		shift
 		;;
 	--torture)
-		checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\|rcuperf\)$' '^--'
+		checkarg --torture "(suite name)" "$#" "$2" '^\(lock\|rcu\|rcuperf\|wake\)$' '^--'
 		TORTURE_SUITE=$2
 		shift
 		;;
tools/testing/selftests/rcutorture/configs/wake/CFLIST new file +1 -0
new file mode 100644
index 000000000000..850c262a6226
@@ -0,0 +1 @@
+STI
tools/testing/selftests/rcutorture/configs/wake/CFcommon new file +2 -0
new file mode 100644
index 000000000000..ffba1816cb6c
@@ -0,0 +1,2 @@
+CONFIG_WAKE_TORTURE_TEST=y
+CONFIG_PRINTK_TIME=y
tools/testing/selftests/rcutorture/configs/wake/STI new file +19 -0
new file mode 100644
index 000000000000..7a17c503b382
@@ -0,0 +1,19 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=16
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_PREEMPT_RCU=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_NO_HZ_IDLE=n
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_TRACE=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_RCU_FANOUT=2
+CONFIG_RCU_FANOUT_LEAF=2
+CONFIG_RCU_NOCB_CPU=n
+CONFIG_DEBUG_LOCK_ALLOC=n
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_KTHREAD_PRIO=2
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
+CONFIG_RCU_EXPERT=y
tools/testing/selftests/rcutorture/configs/wake/STI.boot new file +1 -0
new file mode 100644
index 000000000000..67ac1ad46672
@@ -0,0 +1 @@
+rcupdate.rcu_expedited waketorture.torture_type=sti
tools/testing/selftests/rcutorture/configs/wake/ver_functions.sh new file +43 -0

43 lines not on this page · raw message

Signature · 1 line
2.5.2
#3 lore raw

PATCH 3/8 waketorture: Don't kick unless grace period or request

In reply to Paul E. McKenney

The current code can result in spurious kicks when there are no grace periods in progress and no grace-period-related requests. This is sort of OK for a diagnostic aid, but the resulting ftrace-dump messages in dmesg are annoying. This commit therefore avoids spurious kicks in the common case.

---
 kernel/rcu/tree.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/rcu/tree.c +2 -1
index f433959e9322..88d3f9590322 100644
@@ -1306,7 +1306,8 @@ static void rcu_stall_kick_kthreads(struct rcu_state *rsp)
 	if (!rcu_kick_kthreads)
 		return;
 	j = READ_ONCE(rsp->jiffies_kick_kthreads);
-	if (time_after(jiffies, j) && rsp->gp_kthread) {
+	if (time_after(jiffies, j) && rsp->gp_kthread &&
+	    (rcu_gp_in_progress(rsp) || READ_ONCE(rsp->gp_flags))) {
 		WARN_ONCE(1, "Kicking %s grace-period kthread\n", rsp->name);
 		rcu_ftrace_dump(DUMP_ALL);
 		wake_up_process(rsp->gp_kthread);
Signature · 1 line
2.5.2
#4 lore raw

PATCH 4/8 waketorture: Add utilization measurement

In reply to Paul E. McKenney
---
 kernel/rcu/waketorture.c | 29 ++++++++++++++++++++++++++++-
 lib/Kconfig.debug        |  1 +
 2 files changed, 29 insertions(+), 1 deletion(-)
kernel/rcu/waketorture.c +28 -1
index 75bc547206cc..3068a5c858c8 100644
@@ -81,7 +81,9 @@ static unsigned long *waiter_iter;	/* Number of wait iterations. */
 static bool *waiter_cts;		/* Waiter already checked. */
 static unsigned long *waiter_kicks;	/* Number of waiter starvations. */
 static unsigned long *waiter_ts;	/* Jiffies last run. */
-DEFINE_MUTEX(waiter_mutex);
+static DEFINE_MUTEX(waiter_mutex);
+static DEFINE_PER_CPU(u64, waiter_cputime); /* Nanoseconds. */
+static u64 starttime;
 
 static int torture_runnable = IS_ENABLED(MODULE);
 module_param(torture_runnable, int, 0444);
@@ -133,16 +135,23 @@ static int wake_torture_waiter(void *arg)
 {
 	int i;
 	long me = (long)arg;
+	u64 ts;
 
 	VERBOSE_TOROUT_STRING("wake_torture_waiter task started");
 	set_user_nice(current, MAX_NICE);
 
+	preempt_disable();
+	ts = trace_clock_local();
 	do {
 		waiter_ts[me] = jiffies;
 		smp_mb(); /* Ensure waiter_ts[] written before waiter_cts[]. */
 			  /* Pairs with [A]. */
 		waiter_cts[me] = false;
+		__this_cpu_add(waiter_cputime, trace_clock_local() - ts);
+		preempt_enable();
 		cur_ops->wait(wait_duration);
+		preempt_disable();
+		ts = trace_clock_local();
 		waiter_iter[me]++;
 		for (i = 0; i < nrealwaiters; i++) {
 			if (waiter_done[i] ||
@@ -164,8 +173,14 @@ static int wake_torture_waiter(void *arg)
 				mutex_unlock(&waiter_mutex);
 			}
 		}
+		__this_cpu_add(waiter_cputime, trace_clock_local() - ts);
+		preempt_enable();
 		torture_shutdown_absorb("wake_torture_waiter");
+		preempt_disable();
+		ts = trace_clock_local();
 	} while (!torture_must_stop());
+	__this_cpu_add(waiter_cputime, trace_clock_local() - ts);
+	preempt_enable();
 	mutex_lock(&waiter_mutex);
 	waiter_done[me] = true;
 	mutex_unlock(&waiter_mutex);
@@ -189,6 +204,8 @@ wake_torture_stats_print(void)
 {
 	int i;
 	bool tardy = false;
+	u64 timediff;
+	u64 timetot;
 
 	if (!waiter_done || !waiter_iter || !waiter_cts ||
 	    !waiter_kicks || !waiter_ts) {
@@ -212,6 +229,15 @@ wake_torture_stats_print(void)
 		pr_cont("\n");
 	else
 		TOROUT_STRING(" No tardy kthreads");
+	timediff = (trace_clock_global() - starttime) / 1000;
+	timetot = 0;
+	for_each_possible_cpu(i)
+		timetot += READ_ONCE(per_cpu(waiter_cputime, i));
+	timetot /= nr_cpu_ids;
+	timetot /= timediff;
+	pr_alert("%s" TORTURE_FLAG " timediff: %llu utilization: %llu.%llu nr_cpu_ids: %d\n",
+		 torture_type, timediff,
+		 timetot / 1000ULL, timetot % 1000ULL, nr_cpu_ids);
 }
 
 /*
@@ -290,6 +316,7 @@ wake_torture_init(void)
 
 	if (!torture_init_begin(torture_type, verbose, &torture_runnable))
 		return -EBUSY;
+	starttime = trace_clock_global();
 
 	/* Process args and tell the world that the torturer is on the job. */
 	for (i = 0; i < ARRAY_SIZE(torture_ops); i++) {
lib/Kconfig.debug +1 -0
index f0dcb4c0fe96..c8fb7dad5062 100644
@@ -1403,6 +1403,7 @@ config WAKE_TORTURE_TEST
 	tristate "Torture test for wakeups and CPU hotplug"
 	depends on DEBUG_KERNEL
 	depends on 64BIT
+	depends on TRACE_CLOCK
 	select TORTURE_TEST
 	default n
 	help
Signature · 1 line
2.5.2
#5 lore raw

PATCH 5/8 waketorture: Add hrtimer support

In reply to Paul E. McKenney
---
 kernel/rcu/waketorture.c                           | 50 ++++++++++++++++++----
 tools/testing/selftests/rcutorture/configs/wake/SH | 19 ++++++++
 .../selftests/rcutorture/configs/wake/SH.boot      |  1 +
 3 files changed, 61 insertions(+), 9 deletions(-)
 create mode 100644 tools/testing/selftests/rcutorture/configs/wake/SH
 create mode 100644 tools/testing/selftests/rcutorture/configs/wake/SH.boot
kernel/rcu/waketorture.c +41 -9
index 3068a5c858c8..bf04c65296bd 100644
@@ -62,12 +62,12 @@ torture_param(int, stat_interval, 60,
 	     "Number of seconds between stats printk()s");
 torture_param(bool, verbose, true,
 	     "Enable verbose debugging printk()s");
-torture_param(int, wait_duration, 3,
-	     "Number of jiffies to wait each iteration");
+torture_param(int, wait_duration, 127,
+	     "Number of microseconds to wait each iteration");
 torture_param(int, wait_grace, 20,
 	     "Number of jiffies before complaining about long wait");
 
-static char *torture_type = "sti";
+static char *torture_type = "sh";
 module_param(torture_type, charp, 0444);
 MODULE_PARM_DESC(torture_type, "Type of wait to torture (sti, stui, ...)");
 
@@ -94,18 +94,40 @@ MODULE_PARM_DESC(torture_runnable, "Start waketorture at boot");
  */
 
 struct wake_torture_ops {
-	signed long (*wait)(signed long timeout);
+	void (*wait)(void);
 	const char *name;
 };
 
 static struct wake_torture_ops *cur_ops;
 
 /*
+ * Definitions for schedule_hrtimeout() torture testing.
+ */
+
+static void wait_schedule_hrtimeout(void)
+{
+	ktime_t wait = ns_to_ktime(wait_duration * 1000);
+
+	set_current_state(TASK_UNINTERRUPTIBLE);
+	schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
+}
+
+static struct wake_torture_ops sh_ops = {
+	.wait		= wait_schedule_hrtimeout,
+	.name		= "sh"
+};
+
+/*
  * Definitions for schedule_timeout_interruptible() torture testing.
  */
 
+static void wait_schedule_timeout_interruptible(void)
+{
+	schedule_timeout_interruptible((wait_duration + 999) / 1000);
+}
+
 static struct wake_torture_ops sti_ops = {
-	.wait		= schedule_timeout_interruptible,
+	.wait		= wait_schedule_timeout_interruptible,
 	.name		= "sti"
 };
 
@@ -113,8 +135,13 @@ static struct wake_torture_ops sti_ops = {
  * Definitions for schedule_timeout_uninterruptible() torture testing.
  */
 
+static void wait_schedule_timeout_uninterruptible(void)
+{
+	schedule_timeout_uninterruptible((wait_duration + 999) / 1000);
+}
+
 static struct wake_torture_ops stui_ops = {
-	.wait		= schedule_timeout_uninterruptible,
+	.wait		= wait_schedule_timeout_uninterruptible,
 	.name		= "stui"
 };
 
@@ -149,7 +176,7 @@ static int wake_torture_waiter(void *arg)
 		waiter_cts[me] = false;
 		__this_cpu_add(waiter_cputime, trace_clock_local() - ts);
 		preempt_enable();
-		cur_ops->wait(wait_duration);
+		cur_ops->wait();
 		preempt_disable();
 		ts = trace_clock_local();
 		waiter_iter[me]++;
@@ -167,7 +194,10 @@ static int wake_torture_waiter(void *arg)
 			} else {
 				waiter_cts[i] = true;
 				waiter_kicks[i]++;
-				pr_alert("%s%s wake_torture_waiter(): P%d failing to awaken!\n", torture_type, TORTURE_FLAG, waiter_tasks[i]->pid);
+				pr_alert("%s%s wake_torture_waiter(): P%d (%#lx) failing to awaken!\n",
+					 torture_type, TORTURE_FLAG,
+					 waiter_tasks[i]->pid,
+					 waiter_tasks[i]->state);
 				rcu_ftrace_dump(DUMP_ALL);
 				wake_up_process(waiter_tasks[i]);
 				mutex_unlock(&waiter_mutex);
@@ -312,7 +342,9 @@ wake_torture_init(void)
 {
 	int i;
 	int firsterr = 0;
-	static struct wake_torture_ops *torture_ops[] = { &sti_ops, &stui_ops };
+	static struct wake_torture_ops *torture_ops[] = {
+		&sh_ops, &sti_ops, &stui_ops
+	};
 
 	if (!torture_init_begin(torture_type, verbose, &torture_runnable))
 		return -EBUSY;
tools/testing/selftests/rcutorture/configs/wake/SH new file +19 -0
new file mode 100644
index 000000000000..7a17c503b382
@@ -0,0 +1,19 @@
+CONFIG_SMP=y
+CONFIG_NR_CPUS=16
+CONFIG_PREEMPT_NONE=n
+CONFIG_PREEMPT_VOLUNTARY=n
+CONFIG_PREEMPT=y
+#CHECK#CONFIG_PREEMPT_RCU=y
+CONFIG_HZ_PERIODIC=y
+CONFIG_NO_HZ_IDLE=n
+CONFIG_NO_HZ_FULL=n
+CONFIG_RCU_TRACE=y
+CONFIG_HOTPLUG_CPU=y
+CONFIG_RCU_FANOUT=2
+CONFIG_RCU_FANOUT_LEAF=2
+CONFIG_RCU_NOCB_CPU=n
+CONFIG_DEBUG_LOCK_ALLOC=n
+CONFIG_RCU_BOOST=y
+CONFIG_RCU_KTHREAD_PRIO=2
+CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
+CONFIG_RCU_EXPERT=y
tools/testing/selftests/rcutorture/configs/wake/SH.boot new file +1 -0
new file mode 100644
index 000000000000..a631c878cb27
@@ -0,0 +1 @@
+rcupdate.rcu_expedited waketorture.torture_type=sh
Signature · 1 line
2.5.2
#6 lore raw

PATCH 6/8 torture: Make waketorture always hotplug the same CPU

In reply to Paul E. McKenney

This commit causes waketorture to always hotplug the same CPU, namely, the highest-numbered CPU that can be hotplugged. This will be used by later commits to force race conditions with higher probability.

---
 kernel/rcu/waketorture.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 85 insertions(+), 3 deletions(-)
kernel/rcu/waketorture.c +85 -3
index bf04c65296bd..8568688607ac 100644
@@ -74,6 +74,7 @@ MODULE_PARM_DESC(torture_type, "Type of wait to torture (sti, stui, ...)");
 static int nrealwaiters;
 static struct task_struct **waiter_tasks;
 static struct task_struct *stats_task;
+static struct task_struct *onoff_task;
 
 /* Yes, these cache-thrash, and it is inherent to the concurrency design. */
 static bool *waiter_done;		/* Waiter is done, don't wake. */
@@ -85,6 +86,18 @@ static DEFINE_MUTEX(waiter_mutex);
 static DEFINE_PER_CPU(u64, waiter_cputime); /* Nanoseconds. */
 static u64 starttime;
 
+static int onoff_cpu = -1;
+static long n_offline_attempts;
+static long n_offline_successes;
+static unsigned long sum_offline;
+static int min_offline = -1;
+static int max_offline;
+static long n_online_attempts;
+static long n_online_successes;
+static unsigned long sum_online;
+static int min_online = -1;
+static int max_online;
+
 static int torture_runnable = IS_ENABLED(MODULE);
 module_param(torture_runnable, int, 0444);
 MODULE_PARM_DESC(torture_runnable, "Start waketorture at boot");
@@ -219,6 +232,67 @@ static int wake_torture_waiter(void *arg)
 }
 
 /*
+ * Find a hotpluggable CPU and repeatedly take it online and offline.
+ */
+static int wake_torture_onoff(void *args)
+{
+	int cpu;
+
+	VERBOSE_TOROUT_STRING("wake_torture_onoff task started");
+	if (onoff_holdoff > 0) {
+		VERBOSE_TOROUT_STRING("wake_torture_onoff begin holdoff");
+		schedule_timeout_interruptible(onoff_holdoff * HZ);
+		VERBOSE_TOROUT_STRING("wake_torture_onoff end holdoff");
+	}
+	for_each_online_cpu(cpu) {
+		if (cpu_is_hotpluggable(cpu))
+			onoff_cpu = cpu;
+	}
+	pr_alert("%s" TORTURE_FLAG " wake_torture_onoff: onoff_cpu: %d\n", torture_type, onoff_cpu);
+	if (onoff_cpu < 0)
+		VERBOSE_TOROUT_STRING("wake_torture_onoff: no hotpluggable CPUs!");
+	while (!torture_must_stop() && onoff_cpu >= 0) {
+		if (!torture_offline(onoff_cpu,
+				    &n_offline_attempts, &n_offline_successes,
+				    &sum_offline, &min_offline, &max_offline))
+			torture_online(onoff_cpu,
+				       &n_online_attempts, &n_online_successes,
+				       &sum_online, &min_online, &max_online);
+		schedule_timeout_interruptible(onoff_interval);
+	}
+	torture_kthread_stopping("wake_torture_onoff");
+	return 0;
+}
+
+/*
+ * Initiate waketorture-specific online-offline handling, which
+ * focuses on a single CPU.
+ */
+static int wake_torture_onoff_init(void)
+{
+	int ret = 0;
+
+	if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
+		return ret;
+	if (onoff_interval <= 0)
+		return 0;
+	ret = torture_create_kthread(wake_torture_onoff, NULL, onoff_task);
+	return ret;
+}
+
+/*
+ * Clean up after waketorture-specific online-offline handling.
+ */
+static void wake_torture_onoff_cleanup(void)
+{
+	if (!IS_ENABLED(CONFIG_HOTPLUG_CPU))
+		return;
+	VERBOSE_TOROUT_STRING("Stopping wake_torture_onoff task");
+	kthread_stop(onoff_task);
+	onoff_task = NULL;
+}
+
+/*
  * Print torture statistics.  Caller must ensure that there is only one
  * call to this function at a given time!!!  This is normally accomplished
  * by relying on the module system to only have one copy of the module
@@ -265,9 +339,14 @@ wake_torture_stats_print(void)
 		timetot += READ_ONCE(per_cpu(waiter_cputime, i));
 	timetot /= nr_cpu_ids;
 	timetot /= timediff;
-	pr_alert("%s" TORTURE_FLAG " timediff: %llu utilization: %llu.%llu nr_cpu_ids: %d\n",
+	pr_alert("%s" TORTURE_FLAG " timediff: %llu utilization: %llu.%llu nr_cpu_ids: %d onoff: %ld/%ld:%ld/%ld %d,%d:%d,%d %lu:%lu (HZ=%d)\n",
 		 torture_type, timediff,
-		 timetot / 1000ULL, timetot % 1000ULL, nr_cpu_ids);
+		 timetot / 1000ULL, timetot % 1000ULL, nr_cpu_ids,
+		 n_online_successes, n_online_attempts,
+		 n_offline_successes, n_offline_attempts,
+		 min_online, max_online,
+		 min_offline, max_offline,
+		 sum_online, sum_offline, HZ);
 }
 
 /*
@@ -307,6 +386,9 @@ wake_torture_cleanup(void)
 
 	(void)torture_cleanup_begin();
 
+	if (onoff_task)
+		wake_torture_onoff_cleanup();
+
 	if (waiter_tasks) {
 		for (i = 0; i < nrealwaiters; i++)
 			torture_stop_kthread(wake_torture_waiter,
@@ -414,7 +496,7 @@ wake_torture_init(void)
 	firsterr = torture_shutdown_init(shutdown_secs, wake_torture_cleanup);
 	if (firsterr)
 		goto unwind;
-	firsterr = torture_onoff_init(onoff_holdoff * HZ, onoff_interval);
+	firsterr = wake_torture_onoff_init();
 	if (firsterr)
 		goto unwind;
 	torture_init_end();
Signature · 1 line
2.5.2
#7 lore raw

PATCH 7/8 torture: Make waketorture kill test if no hotpluggable CPUs

In reply to Paul E. McKenney

This commit shuts down the kernel if a shutdown time was specified and if there were no hotpluggable CPUs.

---
 kernel/rcu/waketorture.c | 10 ++++++++--
 1 file changed, 8 insertions(+), 2 deletions(-)
kernel/rcu/waketorture.c +8 -2
index 8568688607ac..f9843eb3f7b7 100644
@@ -248,9 +248,15 @@ static int wake_torture_onoff(void *args)
 		if (cpu_is_hotpluggable(cpu))
 			onoff_cpu = cpu;
 	}
-	pr_alert("%s" TORTURE_FLAG " wake_torture_onoff: onoff_cpu: %d\n", torture_type, onoff_cpu);
-	if (onoff_cpu < 0)
+	if (onoff_cpu < 0) {
 		VERBOSE_TOROUT_STRING("wake_torture_onoff: no hotpluggable CPUs!");
+		if (shutdown_secs > 0) {
+			VERBOSE_TOROUT_STRING("wake_torture_onoff: Shutting down");
+			kernel_power_off();
+			VERBOSE_TOROUT_STRING("wake_torture_onoff: Survived kernel_power_off()?");
+		}
+	}
+	pr_alert("%s" TORTURE_FLAG " wake_torture_onoff: onoff_cpu: %d\n", torture_type, onoff_cpu);
 	while (!torture_must_stop() && onoff_cpu >= 0) {
 		if (!torture_offline(onoff_cpu,
 				    &n_offline_attempts, &n_offline_successes,
Signature · 1 line
2.5.2
#8 lore raw

PATCH 8/8 torture: Affinity waiter tasks away from hotpluggable CPU

In reply to Paul E. McKenney
---
 kernel/rcu/waketorture.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)
kernel/rcu/waketorture.c +19 -0
index f9843eb3f7b7..68be40400f51 100644
@@ -236,7 +236,9 @@ static int wake_torture_waiter(void *arg)
  */
 static int wake_torture_onoff(void *args)
 {
+	cpumask_var_t cm;
 	int cpu;
+	int i;
 
 	VERBOSE_TOROUT_STRING("wake_torture_onoff task started");
 	if (onoff_holdoff > 0) {
@@ -244,6 +246,11 @@ static int wake_torture_onoff(void *args)
 		schedule_timeout_interruptible(onoff_holdoff * HZ);
 		VERBOSE_TOROUT_STRING("wake_torture_onoff end holdoff");
 	}
+
+	/*
+	 * Find the last hotpluggable CPU, and affinity the waiter
+	 * tasks elsewhere.
+	 */
 	for_each_online_cpu(cpu) {
 		if (cpu_is_hotpluggable(cpu))
 			onoff_cpu = cpu;
@@ -257,6 +264,18 @@ static int wake_torture_onoff(void *args)
 		}
 	}
 	pr_alert("%s" TORTURE_FLAG " wake_torture_onoff: onoff_cpu: %d\n", torture_type, onoff_cpu);
+	if (!zalloc_cpumask_var(&cm, GFP_KERNEL)) {
+		VERBOSE_TOROUT_STRING("wake_torture_onoff: Out of memory, no affinity");
+	} else {
+		cpumask_copy(cm, cpu_online_mask);
+		cpumask_clear_cpu(onoff_cpu, cm);
+		if (cpumask_weight(cm) == 0)
+			cpumask_setall(cm);
+		for (i = 0; i < nrealwaiters; i++)
+			set_cpus_allowed_ptr(waiter_tasks[i], cm);
+	}
+
+	/* Cycle the victim CPU online and offline! */
 	while (!torture_must_stop() && onoff_cpu >= 0) {
 		if (!torture_offline(onoff_cpu,
 				    &n_offline_attempts, &n_offline_successes,
Signature · 1 line
2.5.2