diff options
author | Dirk Brandewie <dirk.j.brandewie@intel.com> | 2014-05-29 12:32:24 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2014-06-02 06:45:05 -0400 |
commit | c4ee841f602e5eef8eab673295c49c5b49d7732b (patch) | |
tree | b5ba45afb69212794a1fe53f215992413923e348 | |
parent | f0fe3cd7e12d8290c82284b5c8aee723cbd0371a (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.c | 18 |
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 | ||
65 | struct pstate_data { | 66 | struct 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 | ||
606 | static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu) | 610 | static 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 | ||