diff mbox

[V3] cpuidle: Add validated metrics for idle states

Message ID 20150128074017.13760.80735.stgit@preeti.in.ibm.com
State Accepted
Headers show

Commit Message

Preeti U Murthy Jan. 28, 2015, 7:43 a.m. UTC
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>
---
Changes from V2:

1. Use the average case latency number for nap as opposed to worst case
latency number. The average case latency number has already been coded
for fastsleep,so there is no change there.

Changes from V1:
https://w3-01.ibm.com/stg/linux/ltc/mailinglists/pipermail/sapphire/2014-November/004353.html

1. Use the measured numbers for exit latency and tune only the target_residency
   for optimal power efficiency.
2. Expose both these numbers in the firmware.

 hw/slw.c |   21 ++++++++++++++++++---
 1 file changed, 18 insertions(+), 3 deletions(-)
diff mbox

Patch

diff --git a/hw/slw.c b/hw/slw.c
index b72a0aa..b94ef4f 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);