This is a new C-state policy, based on Thomas's one.
http://lkml.org/lkml/2005/4/19/96

Enhancements:
1. it does all policy calculation before going into idle, so other tasks
can be quickly scheduled after idle.
2. it works w/wo dyntick feature.
3. more tunning parameters and hopefully better policy
4. using pm timer for time accounting, so jiffy doesn't impact the
policy.

Now we use below rules:
1. if cpu activity is high, use C1.
2. if average sleeping time is above or below threshold, do
promotion/demotion.
3. bm activity calculation is similar with current one, but slightly
changed to work with dyntick feature.

It's still not very good. Comments/suggestions are highly appreciated.

Thanks,
Shaohua
---

 linux-2.6.15-rc7-root/drivers/acpi/Kconfig                |    7 
 linux-2.6.15-rc7-root/drivers/acpi/Makefile               |    1 
 linux-2.6.15-rc7-root/drivers/acpi/processor_cstate_new.c |  373 ++++++++++++++
 3 files changed, 381 insertions(+)

diff -puN drivers/acpi/Kconfig~new-policy drivers/acpi/Kconfig
--- linux-2.6.15-rc7/drivers/acpi/Kconfig~new-policy    2006-01-09 
13:28:20.000000000 +0800
+++ linux-2.6.15-rc7-root/drivers/acpi/Kconfig  2006-01-09 13:28:20.000000000 
+0800
@@ -143,6 +143,13 @@ config ACPI_PROCESSOR
          support it.  It is required by several flavors of cpufreq
          Performance-state drivers.
 
+config ACPI_NEW_CSTATE_POLICY
+       tristate "New C-state policy"
+       depends on ACPI_PROCESSOR && EXPERIMENTAL
+       default m
+       help
+        New policy for ACPI C-state. It's friendly with dyn-HZ.
+
 config ACPI_HOTPLUG_CPU
        bool
        depends on ACPI_PROCESSOR && HOTPLUG_CPU
diff -puN drivers/acpi/Makefile~new-policy drivers/acpi/Makefile
--- linux-2.6.15-rc7/drivers/acpi/Makefile~new-policy   2006-01-09 
13:28:20.000000000 +0800
+++ linux-2.6.15-rc7-root/drivers/acpi/Makefile 2006-01-09 13:28:20.000000000 
+0800
@@ -47,6 +47,7 @@ obj-$(CONFIG_ACPI_HOTKEY)     += hotkey.o
 obj-y                          += pci_root.o pci_link.o pci_irq.o pci_bind.o
 obj-$(CONFIG_ACPI_POWER)       += power.o
 obj-$(CONFIG_ACPI_PROCESSOR)   += processor.o
+obj-$(CONFIG_ACPI_NEW_CSTATE_POLICY) += processor_cstate_new.o
 obj-$(CONFIG_ACPI_CONTAINER)   += container.o
 obj-$(CONFIG_ACPI_THERMAL)     += thermal.o
 obj-$(CONFIG_ACPI_SYSTEM)      += system.o event.o
diff -puN /dev/null drivers/acpi/processor_cstate_new.c
--- /dev/null   2006-01-05 19:58:28.436640750 +0800
+++ linux-2.6.15-rc7-root/drivers/acpi/processor_cstate_new.c   2006-01-10 
11:36:40.000000000 +0800
@@ -0,0 +1,373 @@
+/*
+ *  Copyright (C) 2005  Shaohua Li <[EMAIL PROTECTED]>
+ *                     Venkatesh Pallipadi <[EMAIL PROTECTED]>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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, write to the Free Software Foundation, Inc.,
+ *  59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/moduleparam.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/processor.h>
+#include <acpi/processor_cstate_policy.h>
+
+#define ACPI_PROCESSOR_COMPONENT        0x01000000
+#define _COMPONENT              ACPI_PROCESSOR_COMPONENT
+ACPI_MODULE_NAME                ("acpi_processor")
+
+#define MAX_TICK_COUNT 10
+#define PM_TICKS_PER_MS 3579 /* 3.579 ticks per us*/
+
+/* cpu activity threshold */
+static unsigned int cpu_activity = PM_TICKS_PER_MS * 20;
+module_param(cpu_activity, uint, 0644);
+
+/*
+ * bm_history -- bit-mask with a bit per ms of bus-master activity
+ * reduce history for more aggressive entry into C3
+ */
+static unsigned int bm_history = 0xFF;
+module_param(bm_history, uint, 0644);
+static uint bm_activity_measure_time = PM_TICKS_PER_MS * 4; /* 4ms*/
+module_param(bm_activity_measure_time, uint, 0644);
+
+static int param_set_count(const char *val, struct kernel_param *kp)
+{
+       char *endp;
+       uint l;
+
+       if (!val)
+               return -EINVAL;
+
+       l = simple_strtoul(val, &endp, 0);
+       if (endp == val)
+               return -EINVAL;
+       if (l > MAX_TICK_COUNT ) {
+               printk("%s should be <= %d\n",
+                       kp->name, MAX_TICK_COUNT);
+               return -EINVAL;
+       }
+       *((uint *)kp->arg) = l;
+       return 0;
+}
+/* promotion to C2 history count */
+static unsigned int promote_c2_count = 4;
+module_param_call(promote_c2_count, param_set_count, param_get_uint,
+       &promote_c2_count, 0644);
+/* promotion to C3 history count */
+static unsigned int promote_c3_count = 10;
+module_param_call(promote_c3_count, param_set_count, param_get_uint,
+       &promote_c3_count, 0644);
+/* demotion history count */
+static unsigned int demote_count = 1;
+module_param_call(demote_count, param_set_count, param_get_uint,
+       &demote_count, 0644);
+
+struct acpi_processor_threshold {
+       u32 time;
+       u32 ticks; /* threshold ticks */
+       uint *count; /* threshold count */
+       uint bm; /* if need bm check? */
+};
+
+struct acpi_processor_sleep {
+       u32 sleep_ticks[MAX_TICK_COUNT];
+       int current_index;
+       struct acpi_processor_threshold prom;
+       struct acpi_processor_threshold demo;
+};
+
+struct acpi_processor_policy_data {
+       u32 active_timestamp;
+       u32 bm_check_timestamp;
+       struct acpi_processor_sleep sleep[ACPI_PROCESSOR_MAX_POWER];
+};
+
+static int calculate_sleep_average(struct acpi_processor_sleep *p, int c)
+{
+       int i = p->current_index - 1, j;
+       u32 avg = 0;
+       for (j = c; j > 0; j --) {
+               if (i < 0)
+                       i = MAX_TICK_COUNT - 1;
+               avg += p->sleep_ticks[i];
+               i --;
+       }
+       return avg/c;
+}
+
+static int calculate_bm(struct acpi_processor *pr)
+{
+       u32 bm_status = 0;
+       u32 diff;
+       struct acpi_processor_policy_data *p = pr->power.policy_data;
+
+       diff = ticks_elapsed(p->bm_check_timestamp, read_acpi_pmtimer());
+       diff /= bm_activity_measure_time;
+       if (diff > 32)
+               diff = 32;
+       acpi_get_register(ACPI_BITREG_BUS_MASTER_STATUS,
+                       &bm_status, ACPI_MTX_DO_NOT_LOCK);
+       /* no busmaster in last interval */
+       if (!bm_status) {
+               pr->power.bm_activity <<= diff;
+               diff = 0;
+       }
+       while (diff) {
+               /* if we didn't get called, assume there was busmaster activity 
*/
+               diff --;
+               if (diff)
+                       pr->power.bm_activity |= 0x1;
+               pr->power.bm_activity <<= 1;
+       }
+
+       if (bm_status) {
+               pr->power.bm_activity++;
+               acpi_set_register(ACPI_BITREG_BUS_MASTER_STATUS,
+                               1, ACPI_MTX_DO_NOT_LOCK);
+       }
+
+       p->bm_check_timestamp = read_acpi_pmtimer();
+       return pr->power.bm_activity & bm_history;
+}
+
+static int init_this_policy(struct acpi_processor *pr)
+{
+       struct acpi_processor_policy_data *p;
+       unsigned int i;
+       struct acpi_processor_cx *cx;
+       int lower = 0, higher = 0;
+       int state_is_set = 0;
+
+       ACPI_FUNCTION_TRACE("init_this_policy");
+
+       if (pr->power.policy_data) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                       "Other policies are busy\n"));
+               return_VALUE(-EBUSY);
+       }
+       p = kzalloc(sizeof(*p), GFP_KERNEL);
+       if (!p) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                       "Out of memory\n"));
+               return_VALUE(-ENOMEM);
+       }
+
+       /* startup state */
+       for (i=1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
+               cx = &pr->power.states[i];
+               if (!cx->valid)
+                       continue;
+
+               if (!state_is_set)
+                       pr->power.state = cx;
+               state_is_set++;
+               break;
+       }
+
+       if (!state_is_set) {
+               kfree(p);
+               return_VALUE(-ENODEV);
+       }
+
+       for (i = 1; i < ACPI_PROCESSOR_MAX_POWER; i++) {
+               cx = &pr->power.states[i];
+               if (!cx->valid)
+                       continue;
+
+               if (lower) {
+                       pr->power.states[i].demo_state = 
&pr->power.states[lower];
+                       p->sleep[i].demo.ticks = cx->latency_ticks;
+                       p->sleep[i].demo.count = &demote_count;
+                       if (cx->type == ACPI_STATE_C3)
+                               p->sleep[i].demo.bm = 1;
+               }
+
+               lower = i;
+       }
+
+       /* promotion */
+       for (i = (ACPI_PROCESSOR_MAX_POWER - 1); i > 0; i--) {
+               cx = &pr->power.states[i];
+               if (!cx->valid)
+                       continue;
+
+               if (higher) {
+                       pr->power.states[i].prom_state  = 
&pr->power.states[higher];
+                       p->sleep[i].prom.ticks = cx->latency_ticks;
+                       if (cx->type < ACPI_STATE_C2)
+                               p->sleep[i].prom.count = &promote_c2_count;
+                       else
+                               p->sleep[i].prom.count = &promote_c3_count;
+                       if (pr->power.states[higher].type == ACPI_STATE_C3)
+                               p->sleep[i].prom.bm = 1;
+               }
+
+               higher = i;
+       }
+       pr->power.bm_activity = 0;
+       pr->power.policy_data = p;
+       return_VALUE(0);
+}
+
+static int exit_this_policy(struct acpi_processor *pr)
+{
+       struct acpi_processor_policy_data *p;
+
+       ACPI_FUNCTION_TRACE("exit_this_policy");
+
+       if (!pr->power.policy_data) {
+               ACPI_DEBUG_PRINT((ACPI_DB_ERROR,
+                       "Policy data is invalid\n"));
+               return_VALUE(-EINVAL);
+       }
+       p = pr->power.policy_data;
+       pr->power.policy_data = NULL;
+       kfree(p);
+
+       pr->power.bm_activity = 0;
+       return_VALUE(0);
+}
+
+static struct acpi_processor_cx* pre_cx_this_policy(struct acpi_processor *pr)
+{
+       u32 active_diff;
+       struct acpi_processor_cx *next_state;
+       struct acpi_processor_policy_data *p;
+       int index;
+       struct acpi_processor_cx *pro_cx, *dem_cx;
+       struct acpi_processor_sleep *sleep_data;
+       int sleep_ticks;
+       int bm_activity = 0;
+
+       p = pr->power.policy_data;
+       index = pr->power.state - pr->power.states;
+       next_state = pr->power.state;
+
+       /* too many cpu activity, uses C1 */
+       active_diff = ticks_elapsed(p->active_timestamp, read_acpi_pmtimer());
+       if (active_diff > cpu_activity) {
+               next_state = &pr->power.states[ACPI_STATE_C1];
+               goto end;
+       }
+
+       /* bm activity? Demote to bm non-sensitive state */
+       if (pr->flags.bm_check) {
+               bm_activity = calculate_bm(pr);
+               /* this works for both bm activity algorithms */
+               while (p->sleep[index].demo.bm && bm_activity) {
+                       next_state = pr->power.states[index].demo_state;
+                       index = next_state - pr->power.states;
+               }
+               if (next_state != pr->power.state)
+                       goto end;
+       }
+
+       local_irq_enable();
+
+       pro_cx = pr->power.states[index].prom_state;
+       dem_cx = pr->power.states[index].demo_state;
+       sleep_data = &p->sleep[index];
+       /* last sleep time */
+       sleep_ticks = sleep_data->sleep_ticks[sleep_data->current_index - 1 < 0 
?
+               MAX_TICK_COUNT -1 : sleep_data->current_index - 1];
+
+       if (pro_cx && ((pro_cx - pr->power.states) <= max_cstate) &&
+               (sleep_ticks > sleep_data->prom.ticks) &&
+               (calculate_sleep_average(sleep_data, *sleep_data->prom.count) >
+                       sleep_data->prom.ticks)) {
+                       if (!pr->flags.bm_check || !((sleep_data->prom.bm) && 
bm_activity))
+                               next_state = pro_cx;
+                       goto end;
+       }
+
+       if (dem_cx && (sleep_ticks < sleep_data->demo.ticks)) {
+               if (calculate_sleep_average(sleep_data, *sleep_data->demo.count)
+                       < sleep_data->demo.ticks) {
+                       next_state = dem_cx;
+               }
+       }
+
+end:
+       /* Clean previous state's statistics */
+       if (next_state != pr->power.state) {
+               index = pr->power.state - pr->power.states;
+               memset(p->sleep[index].sleep_ticks, 0,
+                       sizeof(p->sleep[index].sleep_ticks));
+       }
+
+       local_irq_disable();
+       return next_state;
+}
+
+static struct acpi_processor_cx* post_cx_this_policy(struct acpi_processor *pr,
+       int sleep_ticks)
+{
+       struct acpi_processor_cx *next_state;
+       struct acpi_processor_policy_data *p;
+       int index;
+       struct acpi_processor_sleep *sleep_data;
+
+       next_state = pr->power.state;
+       p = pr->power.policy_data;
+       index = pr->power.state - pr->power.states;
+       sleep_data = &p->sleep[index];
+
+       sleep_data->sleep_ticks[sleep_data->current_index ++] = sleep_ticks;
+       sleep_data->current_index %= MAX_TICK_COUNT;
+
+       p->active_timestamp = read_acpi_pmtimer();
+       return next_state;
+}
+
+static int update_this_policy(struct acpi_processor *pr)
+{
+       exit_this_policy(pr);
+       init_this_policy(pr);
+       return 0;
+}
+
+static struct acpi_processor_cstate_policy this_policy = {
+       .init = init_this_policy,
+       .exit = exit_this_policy,
+       .update = update_this_policy,
+       .pre_cx = pre_cx_this_policy,
+       .post_cx = post_cx_this_policy,
+};
+
+static int __init policy_init(void)
+{
+       return register_acpi_cstate_policy(&this_policy);
+}
+
+static void __exit policy_exit(void)
+{
+       unregister_acpi_cstate_policy(&this_policy);
+}
+module_init(policy_init);
+module_exit(policy_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Shaohua Li <[EMAIL PROTECTED]>, Venkatesh Pallipadi <[EMAIL 
PROTECTED]>");
_


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

Reply via email to