aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTodd Poynor2012-12-11 18:05:03 -0600
committerArve Hjønnevåg2013-02-19 19:56:06 -0600
commit40403cf3f13a32c677bb4dd27727a5fb8e4f4b30 (patch)
treecc78b2880ec9581c97163b56fa36cd64d6bf60c8
parent68d0fcfb4ec48060f00052ac965c6067326c4d47 (diff)
downloadkernel-common-40403cf3f13a32c677bb4dd27727a5fb8e4f4b30.tar.gz
kernel-common-40403cf3f13a32c677bb4dd27727a5fb8e4f4b30.tar.xz
kernel-common-40403cf3f13a32c677bb4dd27727a5fb8e4f4b30.zip
cpufreq: interactive: adjust load for changes in speed
Add notifier for speed transitions. Keep a count of CPU active microseconds times current frequency, converted to a percentage relative to the current frequency when load is evaluated. Change-Id: I5c27adb11081c50490219784ca57cc46e97fc28c Signed-off-by: Todd Poynor <toddpoynor@google.com>
-rw-r--r--drivers/cpufreq/cpufreq_interactive.c87
1 files changed, 71 insertions, 16 deletions
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index d42bbc2c3f2..e6c8e6fb45f 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -40,8 +40,11 @@ static atomic_t active_count = ATOMIC_INIT(0);
40struct cpufreq_interactive_cpuinfo { 40struct cpufreq_interactive_cpuinfo {
41 struct timer_list cpu_timer; 41 struct timer_list cpu_timer;
42 int timer_idlecancel; 42 int timer_idlecancel;
43 spinlock_t load_lock; /* protects the next 4 fields */
43 u64 time_in_idle; 44 u64 time_in_idle;
44 u64 time_in_idle_timestamp; 45 u64 time_in_idle_timestamp;
46 u64 cputime_speedadj;
47 u64 cputime_speedadj_timestamp;
45 struct cpufreq_policy *policy; 48 struct cpufreq_policy *policy;
46 struct cpufreq_frequency_table *freq_table; 49 struct cpufreq_frequency_table *freq_table;
47 unsigned int target_freq; 50 unsigned int target_freq;
@@ -120,9 +123,13 @@ static void cpufreq_interactive_timer_resched(
120{ 123{
121 mod_timer_pinned(&pcpu->cpu_timer, 124 mod_timer_pinned(&pcpu->cpu_timer,
122 jiffies + usecs_to_jiffies(timer_rate)); 125 jiffies + usecs_to_jiffies(timer_rate));
126 spin_lock(&pcpu->load_lock);
123 pcpu->time_in_idle = 127 pcpu->time_in_idle =
124 get_cpu_idle_time_us(smp_processor_id(), 128 get_cpu_idle_time_us(smp_processor_id(),
125 &pcpu->time_in_idle_timestamp); 129 &pcpu->time_in_idle_timestamp);
130 pcpu->cputime_speedadj = 0;
131 pcpu->cputime_speedadj_timestamp = pcpu->time_in_idle_timestamp;
132 spin_unlock(&pcpu->load_lock);
126} 133}
127 134
128static unsigned int freq_to_targetload(unsigned int freq) 135static unsigned int freq_to_targetload(unsigned int freq)
@@ -147,10 +154,9 @@ static unsigned int freq_to_targetload(unsigned int freq)
147 */ 154 */
148 155
149static unsigned int choose_freq( 156static unsigned int choose_freq(
150 struct cpufreq_interactive_cpuinfo *pcpu, unsigned int curload) 157 struct cpufreq_interactive_cpuinfo *pcpu, unsigned int loadadjfreq)
151{ 158{
152 unsigned int freq = pcpu->policy->cur; 159 unsigned int freq = pcpu->policy->cur;
153 unsigned int loadadjfreq = freq * curload;
154 unsigned int prevfreq, freqmin, freqmax; 160 unsigned int prevfreq, freqmin, freqmax;
155 unsigned int tl; 161 unsigned int tl;
156 int index; 162 int index;
@@ -229,16 +235,36 @@ static unsigned int choose_freq(
229 return freq; 235 return freq;
230} 236}
231 237
232static void cpufreq_interactive_timer(unsigned long data) 238static u64 update_load(int cpu)
233{ 239{
240 struct cpufreq_interactive_cpuinfo *pcpu = &per_cpu(cpuinfo, cpu);
234 u64 now; 241 u64 now;
242 u64 now_idle;
235 unsigned int delta_idle; 243 unsigned int delta_idle;
236 unsigned int delta_time; 244 unsigned int delta_time;
245 u64 active_time;
246
247 now_idle = get_cpu_idle_time_us(cpu, &now);
248 delta_idle = (unsigned int)(now_idle - pcpu->time_in_idle);
249 delta_time = (unsigned int)(now - pcpu->time_in_idle_timestamp);
250 active_time = delta_time - delta_idle;
251 pcpu->cputime_speedadj += active_time * pcpu->policy->cur;
252
253 pcpu->time_in_idle = now_idle;
254 pcpu->time_in_idle_timestamp = now;
255 return now;
256}
257
258static void cpufreq_interactive_timer(unsigned long data)
259{
260 u64 now;
261 unsigned int delta_time;
262 u64 cputime_speedadj;
237 int cpu_load; 263 int cpu_load;
238 struct cpufreq_interactive_cpuinfo *pcpu = 264 struct cpufreq_interactive_cpuinfo *pcpu =
239 &per_cpu(cpuinfo, data); 265 &per_cpu(cpuinfo, data);
240 u64 now_idle;
241 unsigned int new_freq; 266 unsigned int new_freq;
267 unsigned int loadadjfreq;
242 unsigned int index; 268 unsigned int index;
243 unsigned long flags; 269 unsigned long flags;
244 270
@@ -247,26 +273,24 @@ static void cpufreq_interactive_timer(unsigned long data)
247 if (!pcpu->governor_enabled) 273 if (!pcpu->governor_enabled)
248 goto exit; 274 goto exit;
249 275
250 now_idle = get_cpu_idle_time_us(data, &now); 276 spin_lock(&pcpu->load_lock);
251 delta_idle = (unsigned int)(now_idle - pcpu->time_in_idle); 277 now = update_load(data);
252 delta_time = (unsigned int)(now - pcpu->time_in_idle_timestamp); 278 delta_time = (unsigned int)(now - pcpu->cputime_speedadj_timestamp);
279 cputime_speedadj = pcpu->cputime_speedadj;
280 spin_unlock(&pcpu->load_lock);
253 281
254 /* 282 if (WARN_ON_ONCE(!delta_time))
255 * If timer ran less than 1ms after short-term sample started, retry.
256 */
257 if (delta_time < 1000)
258 goto rearm; 283 goto rearm;
259 284
260 if (delta_idle > delta_time) 285 do_div(cputime_speedadj, delta_time);
261 cpu_load = 0; 286 loadadjfreq = (unsigned int)cputime_speedadj * 100;
262 else 287 cpu_load = loadadjfreq / pcpu->target_freq;
263 cpu_load = 100 * (delta_time - delta_idle) / delta_time;
264 288
265 if ((cpu_load >= go_hispeed_load || boost_val) && 289 if ((cpu_load >= go_hispeed_load || boost_val) &&
266 pcpu->target_freq < hispeed_freq) 290 pcpu->target_freq < hispeed_freq)
267 new_freq = hispeed_freq; 291 new_freq = hispeed_freq;
268 else 292 else
269 new_freq = choose_freq(pcpu, cpu_load); 293 new_freq = choose_freq(pcpu, loadadjfreq);
270 294
271 if (pcpu->target_freq >= hispeed_freq && 295 if (pcpu->target_freq >= hispeed_freq &&
272 new_freq > pcpu->target_freq && 296 new_freq > pcpu->target_freq &&
@@ -497,6 +521,32 @@ static void cpufreq_interactive_boost(void)
497 wake_up_process(speedchange_task); 521 wake_up_process(speedchange_task);
498} 522}
499 523
524static int cpufreq_interactive_notifier(
525 struct notifier_block *nb, unsigned long val, void *data)
526{
527 struct cpufreq_freqs *freq = data;
528 struct cpufreq_interactive_cpuinfo *pcpu;
529 int cpu;
530
531 if (val == CPUFREQ_POSTCHANGE) {
532 pcpu = &per_cpu(cpuinfo, freq->cpu);
533
534 for_each_cpu(cpu, pcpu->policy->cpus) {
535 struct cpufreq_interactive_cpuinfo *pjcpu =
536 &per_cpu(cpuinfo, cpu);
537 spin_lock(&pjcpu->load_lock);
538 update_load(cpu);
539 spin_unlock(&pjcpu->load_lock);
540 }
541 }
542
543 return 0;
544}
545
546static struct notifier_block cpufreq_notifier_block = {
547 .notifier_call = cpufreq_interactive_notifier,
548};
549
500static ssize_t show_target_loads( 550static ssize_t show_target_loads(
501 struct kobject *kobj, struct attribute *attr, char *buf) 551 struct kobject *kobj, struct attribute *attr, char *buf)
502{ 552{
@@ -816,6 +866,8 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
816 return rc; 866 return rc;
817 867
818 idle_notifier_register(&cpufreq_interactive_idle_nb); 868 idle_notifier_register(&cpufreq_interactive_idle_nb);
869 cpufreq_register_notifier(
870 &cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
819 break; 871 break;
820 872
821 case CPUFREQ_GOV_STOP: 873 case CPUFREQ_GOV_STOP:
@@ -829,6 +881,8 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
829 if (atomic_dec_return(&active_count) > 0) 881 if (atomic_dec_return(&active_count) > 0)
830 return 0; 882 return 0;
831 883
884 cpufreq_unregister_notifier(
885 &cpufreq_notifier_block, CPUFREQ_TRANSITION_NOTIFIER);
832 idle_notifier_unregister(&cpufreq_interactive_idle_nb); 886 idle_notifier_unregister(&cpufreq_interactive_idle_nb);
833 sysfs_remove_group(cpufreq_global_kobject, 887 sysfs_remove_group(cpufreq_global_kobject,
834 &interactive_attr_group); 888 &interactive_attr_group);
@@ -867,6 +921,7 @@ static int __init cpufreq_interactive_init(void)
867 init_timer_deferrable(&pcpu->cpu_timer); 921 init_timer_deferrable(&pcpu->cpu_timer);
868 pcpu->cpu_timer.function = cpufreq_interactive_timer; 922 pcpu->cpu_timer.function = cpufreq_interactive_timer;
869 pcpu->cpu_timer.data = i; 923 pcpu->cpu_timer.data = i;
924 spin_lock_init(&pcpu->load_lock);
870 } 925 }
871 926
872 spin_lock_init(&target_loads_lock); 927 spin_lock_init(&target_loads_lock);