diff options
author | Liu, Jinsong <jinsong.liu@intel.com> | 2012-03-23 15:08:17 +0000 |
---|---|---|
committer | Liu, Jinsong <jinsong.liu@intel.com> | 2012-03-23 15:08:17 +0000 |
commit | e02af69dc20d4a9319fb6992be3d5bc3e41b49ab (patch) | |
tree | 05c11f24abbadf26e4604a7b496d45a5ffb4509f /xen/common/core_parking.c | |
parent | 2772618c6eb3bc7cdf478f7dfdcb894eac0fe485 (diff) | |
download | xen-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.c | 229 |
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); |