Blob Blame History Raw
From: Mel Gorman <mgorman@suse.de>
Date: Thu, 4 Jan 2018 11:28:56 +0000
Subject: cpufreq: intel_pstate: Temporarily boost P-state when exiting from idle
Patch-mainline: Never, upstream favours power consumption over performance
References: bnc#1066110, bnc#1066845

cpufreq state is inherently per-cpu and while utilisation of a task
influences the p-state selected for a CPU, there is a lag when a task
migrates to a new CPU. The lag before true utilisation is known is related to
both PELT calculations and the frequency samples are taken. For tasks that
recently migrate or are naturally low utilisation, the higher p-states may
never be reached. This patch temporarily boosts p-state when exiting from
idle similar to how it's boosted if a task has blocked recently for IO.
It takes care to avoid boosting for the idle task entering idle and makes
sure the initial target p-state is based on the boosted utilisation.

Signed-off-by: Mel Gorman <mgorman@suse.de>
Signed-off-by: Giovanni Gherdovich <ggherdovich@suse.cz>
---
 drivers/cpufreq/intel_pstate.c |   28 ++++++++++++++++++++++------
 1 file changed, 22 insertions(+), 6 deletions(-)

--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -195,6 +195,7 @@ struct global_params {
  * @update_util:	CPUFreq utility callback information
  * @update_util_set:	CPUFreq utility callback is set
  * @iowait_boost:	iowait-related boost fraction
+ * @idlewait_boost:	idle-related boost fraction
  * @last_update:	Time of the last update.
  * @pstate:		Stores P state limits for this CPU
  * @vid:		Stores VID limits for this CPU
@@ -251,6 +252,7 @@ struct cpudata {
 	bool valid_pss_table;
 #endif
 	unsigned int iowait_boost;
+	unsigned int idle_boost;
 	s16 epp_powersave;
 	s16 epp_policy;
 	s16 epp_default;
@@ -2110,14 +2112,23 @@ static inline int32_t get_target_pstate(
 	busy_frac = div_fp(sample->mperf << cpu->aperf_mperf_shift,
 			   sample->tsc);
 
+	/* IO-wait boosting */
 	boost = cpu->iowait_boost;
 	cpu->iowait_boost >>= 1;
-
 	if (busy_frac < boost)
 		busy_frac = boost;
-
 	sample->busy_scaled = busy_frac * 100;
 
+	/* Exit from long idle boosting */
+	if (cpu->idle_boost && !global.vanilla_policy) {
+		boost = max_t(int32_t, CPUFREQ_SERVER_UTIL_THRESHOLD, cpu->idle_boost);
+		cpu->idle_boost >>= 1;
+		if (busy_frac < boost && !is_idle_task(current)) {
+			busy_frac = boost;
+			sample->busy_scaled = boost * 100;
+		}
+	}
+
 	max_target = global.no_turbo || global.turbo_disabled ?
 			cpu->pstate.max_pstate : cpu->pstate.turbo_pstate;
 	max_target += max_target >> 2;
@@ -2215,11 +2226,16 @@ static void intel_pstate_update_util(str
 			return;
 
 		goto set_pstate;
-	} else if (cpu->iowait_boost) {
-		/* Clear iowait_boost if the CPU may have been idle. */
+	} else {
 		delta_ns = time - cpu->last_update;
-		if (delta_ns > TICK_NSEC)
-			cpu->iowait_boost = 0;
+		if (delta_ns > TICK_NSEC) {
+			/* Clear iowait_boost if the CPU may have been idle. */
+			if (cpu->iowait_boost)
+				cpu->iowait_boost = 0;
+
+			if (!is_idle_task(current))
+				cpu->idle_boost = int_tofp(1);
+		}
 	}
 	cpu->last_update = time;
 	delta_ns = time - cpu->sample.time;