Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'pm-3.15-final' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull intel pstate fixes from Rafael Wysocki:
"Final power management fixes for 3.15

- Taking non-idle time into account when calculating core busy time
was a mistake and led to a performance regression. Since the
problem it was supposed to address is now taken care of in a
different way, we don't need to do it any more, so drop the
non-idle time tracking from intel_pstate. Dirk Brandewie.

- Changing to fixed point math throughout the busy calculation
introduced rounding errors that adversely affect the accuracy of
intel_pstate's computations. Fix from Dirk Brandewie.

- The PID controller algorithm used by intel_pstate assumes that the
time interval between two adjacent samples will always be the same
which is not the case for deferable timers (used by intel_pstate)
when the system is idle. This leads to inaccurate predictions and
artificially increases convergence times for the minimum P-state.
Fix from Dirk Brandewie.

- intel_pstate carries out computations using 32-bit variables that
may overflow for large enough values of APERF/MPERF. Switch to
using 64-bit variables for computations, from Doug Smythies"

* tag 'pm-3.15-final' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
intel_pstate: Improve initial busy calculation
intel_pstate: add sample time scaling
intel_pstate: Correct rounding in busy calculation
intel_pstate: Remove C0 tracking

+31 -21
+31 -21
drivers/cpufreq/intel_pstate.c
··· 40 40 #define BYT_TURBO_VIDS 0x66d 41 41 42 42 43 - #define FRAC_BITS 6 43 + #define FRAC_BITS 8 44 44 #define int_tofp(X) ((int64_t)(X) << FRAC_BITS) 45 45 #define fp_toint(X) ((X) >> FRAC_BITS) 46 - #define FP_ROUNDUP(X) ((X) += 1 << FRAC_BITS) 46 + 47 47 48 48 static inline int32_t mul_fp(int32_t x, int32_t y) 49 49 { ··· 59 59 int32_t core_pct_busy; 60 60 u64 aperf; 61 61 u64 mperf; 62 - unsigned long long tsc; 63 62 int freq; 63 + ktime_t time; 64 64 }; 65 65 66 66 struct pstate_data { ··· 98 98 struct vid_data vid; 99 99 struct _pid pid; 100 100 101 + ktime_t last_sample_time; 101 102 u64 prev_aperf; 102 103 u64 prev_mperf; 103 - unsigned long long prev_tsc; 104 104 struct sample sample; 105 105 }; 106 106 ··· 200 200 pid->last_err = fp_error; 201 201 202 202 result = pterm + mul_fp(pid->integral, pid->i_gain) + dterm; 203 - 203 + if (result >= 0) 204 + result = result + (1 << (FRAC_BITS-1)); 205 + else 206 + result = result - (1 << (FRAC_BITS-1)); 204 207 return (signed int)fp_toint(result); 205 208 } 206 209 ··· 563 560 static inline void intel_pstate_calc_busy(struct cpudata *cpu, 564 561 struct sample *sample) 565 562 { 566 - int32_t core_pct; 567 - int32_t c0_pct; 563 + int64_t core_pct; 564 + int32_t rem; 568 565 569 - core_pct = div_fp(int_tofp((sample->aperf)), 570 - int_tofp((sample->mperf))); 571 - core_pct = mul_fp(core_pct, int_tofp(100)); 572 - FP_ROUNDUP(core_pct); 566 + core_pct = int_tofp(sample->aperf) * int_tofp(100); 567 + core_pct = div_u64_rem(core_pct, int_tofp(sample->mperf), &rem); 573 568 574 - c0_pct = div_fp(int_tofp(sample->mperf), int_tofp(sample->tsc)); 569 + if ((rem << 1) >= int_tofp(sample->mperf)) 570 + core_pct += 1; 575 571 576 572 sample->freq = fp_toint( 577 573 mul_fp(int_tofp(cpu->pstate.max_pstate * 1000), core_pct)); 578 574 579 - sample->core_pct_busy = mul_fp(core_pct, c0_pct); 575 + sample->core_pct_busy = (int32_t)core_pct; 580 576 } 581 577 582 578 static inline void intel_pstate_sample(struct cpudata *cpu) 583 579 { 584 580 u64 aperf, mperf; 585 - unsigned long long tsc; 586 581 587 582 rdmsrl(MSR_IA32_APERF, aperf); 588 583 rdmsrl(MSR_IA32_MPERF, mperf); 589 - tsc = native_read_tsc(); 590 584 591 585 aperf = aperf >> FRAC_BITS; 592 586 mperf = mperf >> FRAC_BITS; 593 - tsc = tsc >> FRAC_BITS; 594 587 588 + cpu->last_sample_time = cpu->sample.time; 589 + cpu->sample.time = ktime_get(); 595 590 cpu->sample.aperf = aperf; 596 591 cpu->sample.mperf = mperf; 597 - cpu->sample.tsc = tsc; 598 592 cpu->sample.aperf -= cpu->prev_aperf; 599 593 cpu->sample.mperf -= cpu->prev_mperf; 600 - cpu->sample.tsc -= cpu->prev_tsc; 601 594 602 595 intel_pstate_calc_busy(cpu, &cpu->sample); 603 596 604 597 cpu->prev_aperf = aperf; 605 598 cpu->prev_mperf = mperf; 606 - cpu->prev_tsc = tsc; 607 599 } 608 600 609 601 static inline void intel_pstate_set_sample_time(struct cpudata *cpu) ··· 612 614 613 615 static inline int32_t intel_pstate_get_scaled_busy(struct cpudata *cpu) 614 616 { 615 - int32_t core_busy, max_pstate, current_pstate; 617 + int32_t core_busy, max_pstate, current_pstate, sample_ratio; 618 + u32 duration_us; 619 + u32 sample_time; 616 620 617 621 core_busy = cpu->sample.core_pct_busy; 618 622 max_pstate = int_tofp(cpu->pstate.max_pstate); 619 623 current_pstate = int_tofp(cpu->pstate.current_pstate); 620 624 core_busy = mul_fp(core_busy, div_fp(max_pstate, current_pstate)); 621 - return FP_ROUNDUP(core_busy); 625 + 626 + sample_time = (pid_params.sample_rate_ms * USEC_PER_MSEC); 627 + duration_us = (u32) ktime_us_delta(cpu->sample.time, 628 + cpu->last_sample_time); 629 + if (duration_us > sample_time * 3) { 630 + sample_ratio = div_fp(int_tofp(sample_time), 631 + int_tofp(duration_us)); 632 + core_busy = mul_fp(core_busy, sample_ratio); 633 + } 634 + 635 + return core_busy; 622 636 } 623 637 624 638 static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)