[PATCH 5/8] add a timeout mechanism to adaptive-locking

From: Gregory Haskins
Date: Mon May 19 2008 - 14:05:58 EST


From: Sven Dietrich <sdietrich@xxxxxxxxxx>

The timeout is useful to eliminate excessive CPU utilization when
waiting for long-held critical sections.

Signed-off-by: Sven Dietrich <sdietrich@xxxxxxxxxx>
Signed-off-by: Peter Morreale <pmorreale@xxxxxxxxxx>
Signed-off-by: Gregory Haskins <ghaskins@xxxxxxxxxx>
---

init/main.c | 6 ++++++
kernel/Kconfig.preempt | 2 ++
kernel/Makefile | 1 +
kernel/rtmutex_adaptive.c | 47 +++++++++++++++++++++++++++++++++++++++++++++
kernel/rtmutex_adaptive.h | 17 +++++++++++++++-
kernel/sysctl.c | 20 +++++++++++++++++++
6 files changed, 92 insertions(+), 1 deletions(-)

diff --git a/init/main.c b/init/main.c
index d64287a..9e3fd5e 100644
--- a/init/main.c
+++ b/init/main.c
@@ -104,6 +104,11 @@ extern void alloc_rtsj_mem_early_setup(void);
#else
static inline void alloc_rtsj_mem_early_setup(void) { }
#endif
+#ifdef CONFIG_ADAPTIVE_RTLOCK
+extern void adaptive_init(void);
+#else
+static inline void adaptive_init(void) { }
+#endif


#ifdef CONFIG_TC
@@ -753,6 +758,7 @@ static void __init do_basic_setup(void)
driver_init();
init_irq_proc();
do_initcalls();
+ adaptive_init();
}

static int __initdata nosoftlockup;
diff --git a/kernel/Kconfig.preempt b/kernel/Kconfig.preempt
index 45d00dc..1650711 100644
--- a/kernel/Kconfig.preempt
+++ b/kernel/Kconfig.preempt
@@ -179,5 +179,7 @@ config ADAPTIVE_RTLOCK
offers a best of both worlds solution since we achieve both
high-throughput and low-latency.

+ The spin time is tuned via: /proc/sys/kernel/rtlock_timeout
+
If unsure, say Y.

diff --git a/kernel/Makefile b/kernel/Makefile
index 9e37671..f37901e 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -35,6 +35,7 @@ ifeq ($(CONFIG_COMPAT),y)
obj-$(CONFIG_FUTEX) += futex_compat.o
endif
obj-$(CONFIG_RT_MUTEXES) += rtmutex.o
+obj-$(CONFIG_ADAPTIVE_RTLOCK) += rtmutex_adaptive.o
obj-$(CONFIG_DEBUG_RT_MUTEXES) += rtmutex-debug.o
obj-$(CONFIG_RT_MUTEX_TESTER) += rtmutex-tester.o
obj-$(CONFIG_PREEMPT_RT) += rt.o
diff --git a/kernel/rtmutex_adaptive.c b/kernel/rtmutex_adaptive.c
new file mode 100644
index 0000000..93e33b9
--- /dev/null
+++ b/kernel/rtmutex_adaptive.c
@@ -0,0 +1,47 @@
+/*
+ * Adaptive RT lock support
+ *
+ * See Documentation/adaptive-locks.txt
+ *
+ * Copyright (C) 2008 Novell, Inc.,
+ * Sven Dietrich, Peter Morreale, and Gregory Haskins
+ *
+ * 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; version 2
+ * of the License.
+ */
+
+#include <linux/sched.h>
+#include "rtmutex_adaptive.h"
+
+unsigned long rtlock_timeout __read_mostly = RTLOCK_DELAY;
+unsigned long rtlock_loops __read_mostly = 0;
+
+/*
+ * Convert nanoseconds to estimated loops
+ */
+static inline void refresh_adaptive_loops(void)
+{
+ rtlock_loops = ((u64) loops_per_jiffy * rtlock_timeout * HZ) >> 30;
+}
+
+void __init adaptive_init(void)
+{
+ refresh_adaptive_loops();
+}
+
+int proc_adaptive_timeout(struct ctl_table *table, int write,
+ struct file *file, void __user *buffer,
+ size_t *length, loff_t *ppos)
+{
+ proc_doulongvec_minmax(table, write, file, buffer, length, ppos);
+
+ refresh_adaptive_loops();
+
+ return 0;
+}
+
+
+
+
diff --git a/kernel/rtmutex_adaptive.h b/kernel/rtmutex_adaptive.h
index 8329e3c..0b53e31 100644
--- a/kernel/rtmutex_adaptive.h
+++ b/kernel/rtmutex_adaptive.h
@@ -15,12 +15,14 @@
#ifndef __KERNEL_RTMUTEX_ADAPTIVE_H
#define __KERNEL_RTMUTEX_ADAPTIVE_H

+#include <linux/sysctl.h>
#include "rtmutex_common.h"


#ifdef CONFIG_ADAPTIVE_RTLOCK
struct adaptive_waiter {
struct task_struct *owner;
+ unsigned long timeout;
};

/*
@@ -42,7 +44,7 @@ adaptive_wait(struct rt_mutex *lock, struct rt_mutex_waiter *waiter,
{
int sleep = 0;

- for (;;) {
+ for (; adaptive->timeout > 0; adaptive->timeout--) {
/*
* If the task was re-awoken, break out completely so we can
* reloop through the lock-acquisition code.
@@ -71,6 +73,9 @@ adaptive_wait(struct rt_mutex *lock, struct rt_mutex_waiter *waiter,
cpu_relax();
}

+ if (adaptive->timeout <= 0)
+ sleep = 1;
+
put_task_struct(adaptive->owner);

return sleep;
@@ -88,9 +93,19 @@ prepare_adaptive_wait(struct rt_mutex *lock, struct adaptive_waiter *adaptive)
get_task_struct(adaptive->owner);
}

+extern int proc_adaptive_timeout(struct ctl_table *table, int write,
+ struct file *file, void __user *buffer,
+ size_t *length, loff_t *ppos);
+
+extern unsigned long rtlock_loops;
+extern unsigned long rtlock_timeout;
+
+#define RTLOCK_DELAY 4000 /* Default delay in nanoseconds */
+
#define DECLARE_ADAPTIVE_WAITER(name) \
struct adaptive_waiter name = { \
.owner = NULL, \
+ .timeout = rtlock_loops, \
}

#else
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 4cf02a8..63e1325 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -57,6 +57,8 @@
#include <asm/io.h>
#endif

+#include "rtmutex_adaptive.h"
+
static int deprecated_sysctl_warning(struct __sysctl_args *args);

#if defined(CONFIG_SYSCTL)
@@ -882,6 +884,24 @@ static struct ctl_table kern_table[] = {
.proc_handler = &proc_dointvec,
},
#endif
+#ifdef CONFIG_ADAPTIVE_RTLOCK
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "rtlock_timeout",
+ .data = &rtlock_timeout,
+ .maxlen = sizeof(unsigned long),
+ .mode = 0644,
+ .proc_handler = &proc_adaptive_timeout,
+ },
+ {
+ .ctl_name = CTL_UNNUMBERED,
+ .procname = "rtlock_loops",
+ .data = &rtlock_loops,
+ .maxlen = sizeof(unsigned long),
+ .mode = 0444,
+ .proc_handler = &proc_doulongvec_minmax,
+ },
+#endif
#ifdef CONFIG_PROC_FS
{
.ctl_name = CTL_UNNUMBERED,

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/