cpufreq: intel_pstate: Use average P-State instead of current P-State
authorPhilippe Longepe <philippe.longepe@linux.intel.com>
Fri, 22 Apr 2016 18:46:09 +0000 (11:46 -0700)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 25 Apr 2016 13:45:11 +0000 (15:45 +0200)
The result returned by pid_calc() is subtracted from current_pstate
(which is the P-State requested during the last period) in order to
obtain the target P-State for the current iteration.

However, current_pstate may not reflect the real current P-State of
the CPU. In particular, that P-State may be higher because of the
frequency sharing per module.

The theory is:
 - The load is the percentage of time spent in C0 and is related to
   the average P-State during the same period.
 - The last requested P-State can be completely different than the
   average P-State (because of frequency sharing or throttling).
 - The P-State shift computed by the pid_calc is based on the load
   computed at average P-State, so the shift must be relative to
   this average P-State.

Using the average P-State instead of current P-State improves power
without significant performance penalty in cases when a task migrates
from one core to other core sharing frequency and voltage.

Performance and power comparison with this patch on Cherry Trail
platform using Android:

Benchmark               ?Perf    ?Power
FishTank                10.45%    3.1%
SmartBench-Gaming       -0.1%   -10.4%
SmartBench-Productivity -0.8%   -10.4%
CandyCrush                n/a   -17.4%
AngryBirds                n/a    -5.9%
videoPlayback             n/a   -13.9%
audioPlayback             n/a    -4.9%
IcyRocks-20-50           0.0%   -38.4%
iozone RR               -0.16%  -1.3%
iozone RW                0.74%  -1.3%

Signed-off-by: Philippe Longepe <philippe.longepe@linux.intel.com>
Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/cpufreq/intel_pstate.c

index 12ae2e6..cfa6a68 100644 (file)
@@ -1061,6 +1061,12 @@ static inline int32_t get_avg_frequency(struct cpudata *cpu)
                cpu->pstate.scaling, cpu->sample.mperf);
 }
 
+static inline int32_t get_avg_pstate(struct cpudata *cpu)
+{
+       return div64_u64(cpu->pstate.max_pstate_physical * cpu->sample.aperf,
+                        cpu->sample.mperf);
+}
+
 static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu)
 {
        struct sample *sample = &cpu->sample;
@@ -1093,7 +1099,7 @@ static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu)
        cpu_load = div64_u64(int_tofp(100) * mperf, sample->tsc);
        cpu->sample.busy_scaled = cpu_load;
 
-       return cpu->pstate.current_pstate - pid_calc(&cpu->pid, cpu_load);
+       return get_avg_pstate(cpu) - pid_calc(&cpu->pid, cpu_load);
 }
 
 static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu)