[Patch 2/2] Xen core parking 2: core parking implementation

From: Liu, Jinsong
Date: Fri Feb 17 2012 - 04:02:57 EST


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@xxxxxxxxx>

diff -r 392e77171d74 xen/common/core_parking.c
--- a/xen/common/core_parking.c Mon Feb 13 11:33:17 2012 +0800
+++ b/xen/common/core_parking.c Thu Feb 16 23:39:57 2012 +0800
@@ -1,13 +1,240 @@
+/*
+ * core_parking.c - implement core parking according to dom0 requirement
+ *
+ * Copyright (C) 2012, Intel Corporation.
+ * Author: Liu, Jinsong <jinsong.liu@xxxxxxxxx>
+ *
+ * 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);

Attachment: xen_core_parking_2.patch
Description: xen_core_parking_2.patch