aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDirk Brandewie <dirk.j.brandewie@intel.com>2014-05-29 12:32:24 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-06-02 06:45:05 -0400
commitc4ee841f602e5eef8eab673295c49c5b49d7732b (patch)
treeb5ba45afb69212794a1fe53f215992413923e348
parentf0fe3cd7e12d8290c82284b5c8aee723cbd0371a (diff)
intel_pstate: add sample time scaling
The PID assumes that samples are of equal time, which for a deferable timers this is not true when the system goes idle. This causes the PID to take a long time to converge to the min P state and depending on the pattern of the idle load can make the P state appear stuck. The hold-off value of three sample times before using the scaling is to give a grace period for applications that have high performance requirements and spend a lot of time idle, The poster child for this behavior is the ffmpeg benchmark in the Phoronix test suite. Cc: 3.14+ <stable@vger.kernel.org> # 3.14+ Signed-off-by: Dirk Brandewie <dirk.j.brandewie@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/cpufreq/intel_pstate.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 3d57e53212d6..2a07588dcbac 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -60,6 +60,7 @@ struct sample {
60 u64 aperf; 60 u64 aperf;
61 u64 mperf; 61 u64 mperf;
62 int freq; 62 int freq;
63 ktime_t time;
63}; 64};
64 65
65struct pstate_data { 66struct pstate_data {
@@ -97,6 +98,7 @@ struct cpudata {
97 struct vid_data vid; 98 struct vid_data vid;
98 struct _pid pid; 99 struct _pid pid;
99 100
101 ktime_t last_sample_time;
100 u64 prev_aperf; 102 u64 prev_aperf;
101 u64 prev_mperf; 103 u64 prev_mperf;
102 struct sample sample; 104 struct sample sample;
@@ -583,6 +585,8 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
583 aperf = aperf >> FRAC_BITS; 585 aperf = aperf >> FRAC_BITS;
584 mperf = mperf >> FRAC_BITS; 586 mperf = mperf >> FRAC_BITS;
585 587
588 cpu->last_sample_time = cpu->sample.time;
589 cpu->sample.time = ktime_get();
586 cpu->sample.aperf = aperf; 590 cpu->sample.aperf = aperf;
587 cpu->sample.mperf = mperf; 591 cpu->sample.mperf = mperf;
588 cpu->sample.aperf -= cpu->prev_aperf; 592 cpu->sample.aperf -= cpu->prev_aperf;
@@ -605,12 +609,24 @@ static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
605 609
606static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu) 610static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu)
607{ 611{
608 int32_t core_busy, max_pstate, current_pstate; 612 int32_t core_busy, max_pstate, current_pstate, sample_ratio;
613 u32 duration_us;
614 u32 sample_time;
609 615
610 core_busy = cpu->sample.core_pct_busy; 616 core_busy = cpu->sample.core_pct_busy;
611 max_pstate = int_tofp(cpu->pstate.max_pstate); 617 max_pstate = int_tofp(cpu->pstate.max_pstate);
612 current_pstate = int_tofp(cpu->pstate.current_pstate); 618 current_pstate = int_tofp(cpu->pstate.current_pstate);
613 core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate)); 619 core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate));
620
621 sample_time = (pid_params.sample_rate_ms * USEC_PER_MSEC);
622 duration_us = (u32) ktime_us_delta(cpu->sample.time,
623 cpu->last_sample_time);
624 if (duration_us > sample_time * 3) {
625 sample_ratio = div_fp(int_tofp(sample_time),
626 int_tofp(duration_us));
627 core_busy = mul_fp(core_busy, sample_ratio);
628 }
629
614 return core_busy; 630 return core_busy;
615} 631}
616 632