aboutsummaryrefslogtreecommitdiffstats
path: root/xen/common/core_parking.c
diff options
context:
space:
mode:
authorLiu, Jinsong <jinsong.liu@intel.com>2012-03-23 15:08:17 +0000
committerLiu, Jinsong <jinsong.liu@intel.com>2012-03-23 15:08:17 +0000
commite02af69dc20d4a9319fb6992be3d5bc3e41b49ab (patch)
tree05c11f24abbadf26e4604a7b496d45a5ffb4509f /xen/common/core_parking.c
parent2772618c6eb3bc7cdf478f7dfdcb894eac0fe485 (diff)
downloadxen-e02af69dc20d4a9319fb6992be3d5bc3e41b49ab.tar.gz
xen-e02af69dc20d4a9319fb6992be3d5bc3e41b49ab.tar.bz2
xen-e02af69dc20d4a9319fb6992be3d5bc3e41b49ab.zip
Xen core parking 2: core parking implementation
This patch implement Xen core parking. Different core parking sequence has different power/performance result, due to cpu socket/core/thread topology. This patch provide power-first and performance-first policies, users can choose core parking policy by their own demand. Signed-off-by: Liu, Jinsong <jinsong.liu@intel.com> Committed-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'xen/common/core_parking.c')
-rw-r--r--xen/common/core_parking.c229
1 files changed, 228 insertions, 1 deletions
diff --git a/xen/common/core_parking.c b/xen/common/core_parking.c
index 635793fba0..3190fb7a30 100644
--- a/xen/common/core_parking.c
+++ b/xen/common/core_parking.c
@@ -1,13 +1,240 @@
+/*
+ * core_parking.c - implement core parking according to dom0 requirement
+ *
+ * Copyright (C) 2012, Intel Corporation.
+ * Author: Liu, Jinsong <jinsong.liu@intel.com>
+ *
+ * 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.
+ */
+
#include <xen/types.h>
+#include <xen/cpu.h>
+#include <xen/init.h>
+#include <xen/cpumask.h>
+#include <asm/percpu.h>
+#include <asm/smp.h>
+
+#define CORE_PARKING_INCREMENT 1
+#define CORE_PARKING_DECREMENT 2
+
+static unsigned int core_parking_power(unsigned int event);
+static unsigned int core_parking_performance(unsigned int event);
static uint32_t cur_idle_nums;
+static unsigned int core_parking_cpunum[NR_CPUS] = {[0 ... NR_CPUS-1] = -1};
+
+static struct core_parking_policy {
+ char name[30];
+ unsigned int (*next)(unsigned int event);
+} *core_parking_policy;
+
+static enum core_parking_controller {
+ POWER_FIRST,
+ PERFORMANCE_FIRST
+} core_parking_controller = POWER_FIRST;
+
+static void __init setup_core_parking_option(char *str)
+{
+ if ( !strcmp(str, "power") )
+ core_parking_controller = POWER_FIRST;
+ else if ( !strcmp(str, "performance") )
+ core_parking_controller = PERFORMANCE_FIRST;
+ else
+ return;
+}
+custom_param("core_parking", setup_core_parking_option);
+
+static unsigned int core_parking_performance(unsigned int event)
+{
+ unsigned int cpu = -1;
+
+ switch ( event )
+ {
+ case CORE_PARKING_INCREMENT:
+ {
+ int core_tmp, core_weight = -1;
+ int sibling_tmp, sibling_weight = -1;
+ cpumask_t core_candidate_map, sibling_candidate_map;
+ cpumask_clear(&core_candidate_map);
+ cpumask_clear(&sibling_candidate_map);
+
+ for_each_cpu(cpu, &cpu_online_map)
+ {
+ if ( cpu == 0 )
+ continue;
+
+ core_tmp = cpumask_weight(per_cpu(cpu_core_mask, cpu));
+ if ( core_weight < core_tmp )
+ {
+ core_weight = core_tmp;
+ cpumask_clear(&core_candidate_map);
+ cpumask_set_cpu(cpu, &core_candidate_map);
+ }
+ else if ( core_weight == core_tmp )
+ cpumask_set_cpu(cpu, &core_candidate_map);
+ }
+
+ for_each_cpu(cpu, &core_candidate_map)
+ {
+ sibling_tmp = cpumask_weight(per_cpu(cpu_sibling_mask, cpu));
+ if ( sibling_weight < sibling_tmp )
+ {
+ sibling_weight = sibling_tmp;
+ cpumask_clear(&sibling_candidate_map);
+ cpumask_set_cpu(cpu, &sibling_candidate_map);
+ }
+ else if ( sibling_weight == sibling_tmp )
+ cpumask_set_cpu(cpu, &sibling_candidate_map);
+ }
+
+ cpu = cpumask_first(&sibling_candidate_map);
+ }
+ break;
+
+ case CORE_PARKING_DECREMENT:
+ {
+ cpu = core_parking_cpunum[cur_idle_nums -1];
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return cpu;
+}
+
+static unsigned int core_parking_power(unsigned int event)
+{
+ unsigned int cpu = -1;
+
+ switch ( event )
+ {
+ case CORE_PARKING_INCREMENT:
+ {
+ int core_tmp, core_weight = NR_CPUS + 1;
+ int sibling_tmp, sibling_weight = NR_CPUS + 1;
+ cpumask_t core_candidate_map, sibling_candidate_map;
+ cpumask_clear(&core_candidate_map);
+ cpumask_clear(&sibling_candidate_map);
+
+ for_each_cpu(cpu, &cpu_online_map)
+ {
+ if ( cpu == 0 )
+ continue;
+
+ core_tmp = cpumask_weight(per_cpu(cpu_core_mask, cpu));
+ if ( core_weight > core_tmp )
+ {
+ core_weight = core_tmp;
+ cpumask_clear(&core_candidate_map);
+ cpumask_set_cpu(cpu, &core_candidate_map);
+ }
+ else if ( core_weight == core_tmp )
+ cpumask_set_cpu(cpu, &core_candidate_map);
+ }
+
+ for_each_cpu(cpu, &core_candidate_map)
+ {
+ sibling_tmp = cpumask_weight(per_cpu(cpu_sibling_mask, cpu));
+ if ( sibling_weight > sibling_tmp )
+ {
+ sibling_weight = sibling_tmp;
+ cpumask_clear(&sibling_candidate_map);
+ cpumask_set_cpu(cpu, &sibling_candidate_map);
+ }
+ else if ( sibling_weight == sibling_tmp )
+ cpumask_set_cpu(cpu, &sibling_candidate_map);
+ }
+
+ cpu = cpumask_first(&sibling_candidate_map);
+ }
+ break;
+
+ case CORE_PARKING_DECREMENT:
+ {
+ cpu = core_parking_cpunum[cur_idle_nums -1];
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return cpu;
+}
long core_parking_helper(void *data)
{
- return 0;
+ uint32_t idle_nums = (unsigned long)data;
+ unsigned int cpu;
+ int ret = 0;
+
+ if ( !core_parking_policy )
+ return -EINVAL;
+
+ while ( cur_idle_nums < idle_nums )
+ {
+ cpu = core_parking_policy->next(CORE_PARKING_INCREMENT);
+ ret = cpu_down(cpu);
+ if ( ret )
+ return ret;
+ core_parking_cpunum[cur_idle_nums++] = cpu;
+ }
+
+ while ( cur_idle_nums > idle_nums )
+ {
+ cpu = core_parking_policy->next(CORE_PARKING_DECREMENT);
+ ret = cpu_up(cpu);
+ if ( ret )
+ return ret;
+ core_parking_cpunum[--cur_idle_nums] = -1;
+ }
+
+ return ret;
}
uint32_t get_cur_idle_nums(void)
{
return cur_idle_nums;
}
+
+static struct core_parking_policy power_first = {
+ .name = "power",
+ .next = core_parking_power,
+};
+
+static struct core_parking_policy performance_first = {
+ .name = "performance",
+ .next = core_parking_performance,
+};
+
+static int register_core_parking_policy(struct core_parking_policy *policy)
+{
+ if ( !policy || !policy->next )
+ return -EINVAL;
+
+ core_parking_policy = policy;
+ return 0;
+}
+
+static int __init core_parking_init(void)
+{
+ int ret = 0;
+
+ if ( core_parking_controller == PERFORMANCE_FIRST )
+ ret = register_core_parking_policy(&performance_first);
+ else
+ ret = register_core_parking_policy(&power_first);
+
+ return ret;
+}
+__initcall(core_parking_init);