aboutsummaryrefslogtreecommitdiff
path: root/hw/slw.c
diff options
context:
space:
mode:
authorPreeti U Murthy <preeti@linux.vnet.ibm.com>2015-01-28 13:13:06 +0530
committerStewart Smith <stewart@linux.vnet.ibm.com>2015-01-28 19:44:06 +1100
commit0d7b1161a5ac221372a6b3d515af0017f3ea51fc (patch)
tree76bd2a2e34d24ac258ebf5f31b475146febb42ff /hw/slw.c
parent959079e2ca18e00e7aff7febe1733bc76349dc5c (diff)
downloadskiboot-0d7b1161a5ac221372a6b3d515af0017f3ea51fc.zip
skiboot-0d7b1161a5ac221372a6b3d515af0017f3ea51fc.tar.gz
skiboot-0d7b1161a5ac221372a6b3d515af0017f3ea51fc.tar.bz2
cpuidle: Add validated metrics for idle states
The idle states are characterized by latency and residency numbers which determine the breakeven point for entry into them. The latency is a measure of the exit overhead from the idle state and residency is the minimum amount of time that a CPU must be predicted to be idle so as to reap the powersavings from entering into that idle state. These numbers are made use of by the cpuidle governors in the kernel to arrive at the appropriate idle state that a CPU must enter into when there is no work to be done. Today the kernel uses the latency numbers given by the firmware. To arrive at a value for residency, it uses a multiplier of 10 on the latency number. The latency number coded in the firmware is inaccurate as is the technique for calculating the residency. This patch codes in the the measured latency numbers for the idle states. The residency numbers have been arrived at experimentally after ensuring that the performance of latency sensitive workloads do not regress while allowing deeper idle states to be entered into during low load situations. The kernel is expected to use these values for optimal power efficiency. Signed-off-by: Preeti U Murthy <preeti@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
Diffstat (limited to 'hw/slw.c')
-rw-r--r--hw/slw.c21
1 files changed, 18 insertions, 3 deletions
diff --git a/hw/slw.c b/hw/slw.c
index 669d0c7..cd746af 100644
--- a/hw/slw.c
+++ b/hw/slw.c
@@ -395,6 +395,7 @@ static bool idle_prepare_core(struct proc_chip *chip, struct cpu_thread *c)
struct cpu_idle_states {
char name[MAX_NAME_LEN];
u32 latency_ns;
+ u32 residency_ns;
u32 flags;
u64 pmicr;
u64 pmicr_mask;
@@ -427,7 +428,8 @@ struct cpu_idle_states {
static struct cpu_idle_states power7_cpu_idle_states[] = {
{ /* nap */
.name = "nap",
- .latency_ns = 1000,
+ .latency_ns = 4000,
+ .residency_ns = 100000,
.flags = 0*IDLE_DEC_STOP \
| 0*IDLE_TB_STOP \
| 1*IDLE_LOSE_USER_CONTEXT \
@@ -444,7 +446,8 @@ static struct cpu_idle_states power7_cpu_idle_states[] = {
static struct cpu_idle_states power8_cpu_idle_states[] = {
{ /* nap */
.name = "nap",
- .latency_ns = 1000,
+ .latency_ns = 4000,
+ .residency_ns = 100000,
.flags = 0*IDLE_DEC_STOP \
| 0*IDLE_TB_STOP \
| 1*IDLE_LOSE_USER_CONTEXT \
@@ -456,7 +459,8 @@ static struct cpu_idle_states power8_cpu_idle_states[] = {
.pmicr_mask = 0 },
{ /* fast sleep (with workaround) */
.name = "fastsleep_",
- .latency_ns = 100000,
+ .latency_ns = 40000,
+ .residency_ns = 300000000,
.flags = 1*IDLE_DEC_STOP \
| 1*IDLE_TB_STOP \
| 1*IDLE_LOSE_USER_CONTEXT \
@@ -470,6 +474,8 @@ static struct cpu_idle_states power8_cpu_idle_states[] = {
{ /* Winkle */
.name = "winkle",
.latency_ns = 10000000,
+ .residency_ns = 1000000000, /* Placeholder only.Winkle is not used by
+ the cpuidle subsystem today */
.flags = 1*IDLE_DEC_STOP \
| 1*IDLE_TB_STOP \
| 1*IDLE_LOSE_USER_CONTEXT \
@@ -496,6 +502,7 @@ static void add_cpu_idle_state_properties(void)
/* Buffers to hold idle state properties */
char *name_buf;
u32 *latency_ns_buf;
+ u32 *residency_ns_buf;
u32 *flags_buf;
u64 *pmicr_buf;
u64 *pmicr_mask_buf;
@@ -571,6 +578,7 @@ static void add_cpu_idle_state_properties(void)
/* Allocate memory to idle state property buffers. */
name_buf = (char *) malloc(nr_states * sizeof(char) * MAX_NAME_LEN);
latency_ns_buf = (u32 *) malloc(nr_states * sizeof(u32));
+ residency_ns_buf= (u32 *) malloc(nr_states * sizeof(u32));
flags_buf = (u32 *) malloc(nr_states * sizeof(u32));
pmicr_buf = (u64 *) malloc(nr_states * sizeof(u64));
pmicr_mask_buf = (u64 *) malloc(nr_states * sizeof(u64));
@@ -594,6 +602,9 @@ static void add_cpu_idle_state_properties(void)
*latency_ns_buf = cpu_to_fdt32(states[i].latency_ns);
latency_ns_buf++;
+ *residency_ns_buf = cpu_to_fdt32(states[i].residency_ns);
+ residency_ns_buf++;
+
*flags_buf = cpu_to_fdt32(states[i].flags);
flags_buf++;
@@ -612,6 +623,7 @@ static void add_cpu_idle_state_properties(void)
/* Point buffer pointers back to beginning of the buffer */
name_buf -= name_buf_len;
latency_ns_buf -= num_supported_idle_states;
+ residency_ns_buf -= num_supported_idle_states;
flags_buf -= num_supported_idle_states;
pmicr_buf -= num_supported_idle_states;
pmicr_mask_buf -= num_supported_idle_states;
@@ -621,6 +633,8 @@ static void add_cpu_idle_state_properties(void)
name_buf_len* sizeof(char));
dt_add_property(power_mgt, "ibm,cpu-idle-state-latencies-ns",
latency_ns_buf, num_supported_idle_states * sizeof(u32));
+ dt_add_property(power_mgt, "ibm,cpu-idle-state-residency-ns",
+ residency_ns_buf, num_supported_idle_states * sizeof(u32));
dt_add_property(power_mgt, "ibm,cpu-idle-state-flags", flags_buf,
num_supported_idle_states * sizeof(u32));
dt_add_property(power_mgt, "ibm,cpu-idle-state-pmicr", pmicr_buf,
@@ -630,6 +644,7 @@ static void add_cpu_idle_state_properties(void)
free(name_buf);
free(latency_ns_buf);
+ free(residency_ns_buf);
free(flags_buf);
free(pmicr_buf);
free(pmicr_mask_buf);