[RFC][PATCH 3/3] add the 'menu' cpuidle governor

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This patch adds the 'menu' governor, as was described in my first email.

Thanks,
Adam

 Kconfig            |   11 +++
 governors/Makefile |    1
 governors/menu.c   |  152 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 164 insertions(+)


diff -urN a/drivers/cpuidle/governors/Makefile b/drivers/cpuidle/governors/Makefile
--- a/drivers/cpuidle/governors/Makefile	2007-03-23 23:09:45.000000000 -0400
+++ b/drivers/cpuidle/governors/Makefile	2007-03-24 02:10:29.000000000 -0400
@@ -3,3 +3,4 @@
 #
 
 obj-$(CONFIG_CPU_IDLE_GOV_LADDER) += ladder.o
+obj-$(CONFIG_CPU_IDLE_GOV_MENU) += menu.o
diff -urN a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
--- a/drivers/cpuidle/governors/menu.c	1969-12-31 19:00:00.000000000 -0500
+++ b/drivers/cpuidle/governors/menu.c	2007-03-23 23:51:15.000000000 -0400
@@ -0,0 +1,152 @@
+/*
+ * menu.c - the menu idle governor
+ *
+ * Copyright (C) 2006-2007 Adam Belay <abelay@xxxxxxxxxx>
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include <linux/kernel.h>
+#include <linux/cpuidle.h>
+#include <linux/latency.h>
+#include <linux/time.h>
+#include <linux/ktime.h>
+#include <linux/tick.h>
+#include <linux/hrtimer.h>
+
+#define BM_HOLDOFF	20000	/* 20 ms */
+
+struct menu_device {
+	int		last_state_idx;
+	int		deepest_bm_state;
+
+	int		break_last_us;
+	int		break_elapsed_us;
+
+	int		bm_elapsed_us;
+	int		bm_holdoff_us;
+
+	unsigned long	idle_jiffies;
+};
+
+static DEFINE_PER_CPU(struct menu_device, menu_devices);
+
+/**
+ * menu_select - selects the next idle state to enter
+ * @dev: the CPU
+ */
+static int menu_select(struct cpuidle_device *dev)
+{
+	struct menu_device *data = &__get_cpu_var(menu_devices);
+	int i, expected_us, max_state = dev->state_count;
+
+	/* discard BM history because it is sticky */
+	cpuidle_get_bm_activity();
+
+	/* determine the expected residency time */
+	expected_us = (s32) ktime_to_ns(tick_nohz_get_sleep_length()) / 1000;
+	expected_us = min(expected_us, data->break_last_us);
+
+	/* determine the maximum state compatible with current BM status */
+	if (cpuidle_get_bm_activity())
+		data->bm_elapsed_us = 0;
+	if (data->bm_elapsed_us <= data->bm_holdoff_us)
+		max_state = data->deepest_bm_state + 1;
+
+	/* find the deepest idle state that satisfies our constraints */
+	for (i = 1; i < max_state; i++) {
+		struct cpuidle_state *s = &dev->states[i];
+		if (s->target_residency > expected_us)
+			break;
+		if (s->exit_latency > system_latency_constraint())
+			break;
+	}
+
+	data->last_state_idx = i - 1;
+	data->idle_jiffies = tick_nohz_get_idle_jiffies();
+	return i - 1;
+}
+
+/**
+ * menu_reflect - attempts to guess what happened after entry
+ * @dev: the CPU
+ *
+ * NOTE: it's important to be fast here because this operation will add to
+ *       the overall exit latency.
+ */
+static void menu_reflect(struct cpuidle_device *dev)
+{
+	struct menu_device *data = &__get_cpu_var(menu_devices);
+	int last_idx = data->last_state_idx;
+	int measured_us = cpuidle_get_last_residency(dev);
+	struct cpuidle_state *target = &dev->states[last_idx];
+
+	/*
+	 * Ugh, this idle state doesn't support residency measurements, so we
+	 * are basically lost in the dark.  As a compromise, assume we slept
+	 * for one full standard timer tick.  However, be aware that this
+	 * could potentially result in a suboptimal state transition.
+	 */
+	if (!(target->flags & CPUIDLE_FLAG_TIME_VALID))
+		measured_us = USEC_PER_SEC / HZ;
+
+	data->bm_elapsed_us += measured_us;
+	data->break_elapsed_us += measured_us;
+
+	/*
+	 * Did something other than the timer interrupt cause the break event?
+	 */
+	if (tick_nohz_get_idle_jiffies() == data->idle_jiffies) {
+		data->break_last_us = data->break_elapsed_us;
+		data->break_elapsed_us = 0;
+	}
+}
+
+/**
+ * menu_scan_device - scans a CPU's states and does setup
+ * @dev: the CPU
+ */
+static void menu_scan_device(struct cpuidle_device *dev)
+{
+	struct menu_device *data = &per_cpu(menu_devices, dev->cpu);
+	int i;
+
+	data->last_state_idx = 0;
+	data->break_last_us = 0;
+	data->break_elapsed_us = 0;
+	data->bm_elapsed_us = 0;
+	data->bm_holdoff_us = BM_HOLDOFF;
+
+	for (i = 1; i < dev->state_count; i++)
+		if (dev->states[i].flags & CPUIDLE_FLAG_CHECK_BM)
+			break;
+	data->deepest_bm_state = i - 1;
+}
+
+struct cpuidle_governor menu_governor = {
+	.name =		"menu",
+	.scan =		menu_scan_device,
+	.select =	menu_select,
+	.reflect =	menu_reflect,
+	.owner =	THIS_MODULE,
+};
+
+/**
+ * init_menu - initializes the governor
+ */
+static int __init init_menu(void)
+{
+	return cpuidle_register_governor(&menu_governor);
+}
+
+/**
+ * exit_menu - exits the governor
+ */
+static void __exit exit_menu(void)
+{
+	cpuidle_unregister_governor(&menu_governor);
+}
+
+MODULE_LICENSE("GPL");
+module_init(init_menu);
+module_exit(exit_menu);
diff -urN a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
--- a/drivers/cpuidle/Kconfig	2007-03-23 23:09:45.000000000 -0400
+++ b/drivers/cpuidle/Kconfig	2007-03-24 02:18:19.000000000 -0400
@@ -23,6 +23,17 @@
 	  states using residency time and bus master activity as metrics.  This
 	  algorithm was originally introduced in the old ACPI processor driver.
 
+config CPU_IDLE_GOV_MENU
+	tristate "'menu' governor"
+	depends on CPU_IDLE && NO_HZ
+	default y
+	help
+	  This cpuidle governor evaluates all available states and chooses the
+	  deepest state that meets all of the following constraints: BM activity,
+	  expected time until next timer interrupt, and last break event time
+	  delta.  It is designed to minimize power consumption.  Currently
+	  dynticks is required.
+
 endif	# CPU_IDLE
 
 endmenu


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

[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux