aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlexey Starikovskiy <alexey_y_starikovskiy@linux.intel.com>2006-07-31 14:28:12 -0400
committerDave Jones <davej@redhat.com>2006-08-11 17:59:57 -0400
commit05ca0350e8caa91a5ec9961c585c98005b6934ea (patch)
tree16eb1080f5db361dcd18821f7204b8edf5ffb698
parent1ce28d6b19112a7c76af8e971e2de3109d19a943 (diff)
[CPUFREQ][2/2] ondemand: updated add powersave_bias tunable
ondemand selects the minimum frequency that can retire a workload with negligible idle time -- ideally resulting in the highest performance/power efficiency with negligible performance impact. But on some systems and some workloads, this algorithm is more performance biased than necessary, and de-tuning it a bit to allow some performance impact can save measurable power. This patch adds a "powersave_bias" tunable to ondemand to allow it to reduce its target frequency by a specified percent. By default, the powersave_bias is 0 and has no effect. powersave_bias is in units of 0.1%, so it has an effective range of 1 through 1000, resulting in 0.1% to 100% impact. In practice, users will not be able to detect a difference between 0.1% increments, but 1.0% increments turned out to be too large. Also, the max value of 1000 (100%) would simply peg the system in its deepest power saving P-state, unless the processor really has a hardware P-state at 0Hz:-) For example, If ondemand requests 2.0GHz based on utilization, and powersave_bias=100, this code will knock 10% off the target and seek a target of 1.8GHz instead of 2.0GHz until the next sampling. If 1.8 is an exact match with an hardware frequency we use it, otherwise we average our time between the frequency next higher than 1.8 and next lower than 1.8. Note that a user or administrative program can change powersave_bias at run-time depending on how they expect the system to be used. Signed-off-by: Venkatesh Pallipadi <venkatesh.pallipadi at intel.com> Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy at intel.com> Signed-off-by: Dave Jones <davej@redhat.com>
-rw-r--r--drivers/cpufreq/cpufreq_ondemand.c157
1 files changed, 140 insertions, 17 deletions
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index f507a869acbc..34874c2f1885 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -55,6 +55,10 @@ struct cpu_dbs_info_s {
55 struct cpufreq_policy *cur_policy; 55 struct cpufreq_policy *cur_policy;
56 struct work_struct work; 56 struct work_struct work;
57 unsigned int enable; 57 unsigned int enable;
58 struct cpufreq_frequency_table *freq_table;
59 unsigned int freq_lo;
60 unsigned int freq_lo_jiffies;
61 unsigned int freq_hi_jiffies;
58}; 62};
59static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info); 63static DEFINE_PER_CPU(struct cpu_dbs_info_s, cpu_dbs_info);
60 64
@@ -72,15 +76,15 @@ static DEFINE_MUTEX(dbs_mutex);
72 76
73static struct workqueue_struct *kondemand_wq; 77static struct workqueue_struct *kondemand_wq;
74 78
75struct dbs_tuners { 79static struct dbs_tuners {
76 unsigned int sampling_rate; 80 unsigned int sampling_rate;
77 unsigned int up_threshold; 81 unsigned int up_threshold;
78 unsigned int ignore_nice; 82 unsigned int ignore_nice;
79}; 83 unsigned int powersave_bias;
80 84} dbs_tuners_ins = {
81static struct dbs_tuners dbs_tuners_ins = {
82 .up_threshold = DEF_FREQUENCY_UP_THRESHOLD, 85 .up_threshold = DEF_FREQUENCY_UP_THRESHOLD,
83 .ignore_nice = 0, 86 .ignore_nice = 0,
87 .powersave_bias = 0,
84}; 88};
85 89
86static inline cputime64_t get_cpu_idle_time(unsigned int cpu) 90static inline cputime64_t get_cpu_idle_time(unsigned int cpu)
@@ -96,6 +100,69 @@ static inline cputime64_t get_cpu_idle_time(unsigned int cpu)
96 return retval; 100 return retval;
97} 101}
98 102
103/*
104 * Find right freq to be set now with powersave_bias on.
105 * Returns the freq_hi to be used right now and will set freq_hi_jiffies,
106 * freq_lo, and freq_lo_jiffies in percpu area for averaging freqs.
107 */
108unsigned int powersave_bias_target(struct cpufreq_policy *policy,
109 unsigned int freq_next, unsigned int relation)
110{
111 unsigned int freq_req, freq_reduc, freq_avg;
112 unsigned int freq_hi, freq_lo;
113 unsigned int index = 0;
114 unsigned int jiffies_total, jiffies_hi, jiffies_lo;
115 struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, policy->cpu);
116
117 if (!dbs_info->freq_table) {
118 dbs_info->freq_lo = 0;
119 dbs_info->freq_lo_jiffies = 0;
120 return freq_next;
121 }
122
123 cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_next,
124 relation, &index);
125 freq_req = dbs_info->freq_table[index].frequency;
126 freq_reduc = freq_req * dbs_tuners_ins.powersave_bias / 1000;
127 freq_avg = freq_req - freq_reduc;
128
129 /* Find freq bounds for freq_avg in freq_table */
130 index = 0;
131 cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg,
132 CPUFREQ_RELATION_H, &index);
133 freq_lo = dbs_info->freq_table[index].frequency;
134 index = 0;
135 cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg,
136 CPUFREQ_RELATION_L, &index);
137 freq_hi = dbs_info->freq_table[index].frequency;
138
139 /* Find out how long we have to be in hi and lo freqs */
140 if (freq_hi == freq_lo) {
141 dbs_info->freq_lo = 0;
142 dbs_info->freq_lo_jiffies = 0;
143 return freq_lo;
144 }
145 jiffies_total = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
146 jiffies_hi = (freq_avg - freq_lo) * jiffies_total;
147 jiffies_hi += ((freq_hi - freq_lo) / 2);
148 jiffies_hi /= (freq_hi - freq_lo);
149 jiffies_lo = jiffies_total - jiffies_hi;
150 dbs_info->freq_lo = freq_lo;
151 dbs_info->freq_lo_jiffies = jiffies_lo;
152 dbs_info->freq_hi_jiffies = jiffies_hi;
153 return freq_hi;
154}
155
156static void ondemand_powersave_bias_init(void)
157{
158 int i;
159 for_each_online_cpu(i) {
160 struct cpu_dbs_info_s *dbs_info = &per_cpu(cpu_dbs_info, i);
161 dbs_info->freq_table = cpufreq_frequency_get_table(i);
162 dbs_info->freq_lo = 0;
163 }
164}
165
99/************************** sysfs interface ************************/ 166/************************** sysfs interface ************************/
100static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf) 167static ssize_t show_sampling_rate_max(struct cpufreq_policy *policy, char *buf)
101{ 168{
@@ -124,6 +191,7 @@ static ssize_t show_##file_name \
124show_one(sampling_rate, sampling_rate); 191show_one(sampling_rate, sampling_rate);
125show_one(up_threshold, up_threshold); 192show_one(up_threshold, up_threshold);
126show_one(ignore_nice_load, ignore_nice); 193show_one(ignore_nice_load, ignore_nice);
194show_one(powersave_bias, powersave_bias);
127 195
128static ssize_t store_sampling_rate(struct cpufreq_policy *unused, 196static ssize_t store_sampling_rate(struct cpufreq_policy *unused,
129 const char *buf, size_t count) 197 const char *buf, size_t count)
@@ -198,6 +266,27 @@ static ssize_t store_ignore_nice_load(struct cpufreq_policy *policy,
198 return count; 266 return count;
199} 267}
200 268
269static ssize_t store_powersave_bias(struct cpufreq_policy *unused,
270 const char *buf, size_t count)
271{
272 unsigned int input;
273 int ret;
274 ret = sscanf(buf, "%u", &input);
275
276 if (ret != 1)
277 return -EINVAL;
278
279 if (input > 1000)
280 input = 1000;
281
282 mutex_lock(&dbs_mutex);
283 dbs_tuners_ins.powersave_bias = input;
284 ondemand_powersave_bias_init();
285 mutex_unlock(&dbs_mutex);
286
287 return count;
288}
289
201#define define_one_rw(_name) \ 290#define define_one_rw(_name) \
202static struct freq_attr _name = \ 291static struct freq_attr _name = \
203__ATTR(_name, 0644, show_##_name, store_##_name) 292__ATTR(_name, 0644, show_##_name, store_##_name)
@@ -205,6 +294,7 @@ __ATTR(_name, 0644, show_##_name, store_##_name)
205define_one_rw(sampling_rate); 294define_one_rw(sampling_rate);
206define_one_rw(up_threshold); 295define_one_rw(up_threshold);
207define_one_rw(ignore_nice_load); 296define_one_rw(ignore_nice_load);
297define_one_rw(powersave_bias);
208 298
209static struct attribute * dbs_attributes[] = { 299static struct attribute * dbs_attributes[] = {
210 &sampling_rate_max.attr, 300 &sampling_rate_max.attr,
@@ -212,6 +302,7 @@ static struct attribute * dbs_attributes[] = {
212 &sampling_rate.attr, 302 &sampling_rate.attr,
213 &up_threshold.attr, 303 &up_threshold.attr,
214 &ignore_nice_load.attr, 304 &ignore_nice_load.attr,
305 &powersave_bias.attr,
215 NULL 306 NULL
216}; 307};
217 308
@@ -234,6 +325,7 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
234 if (!this_dbs_info->enable) 325 if (!this_dbs_info->enable)
235 return; 326 return;
236 327
328 this_dbs_info->freq_lo = 0;
237 policy = this_dbs_info->cur_policy; 329 policy = this_dbs_info->cur_policy;
238 cur_jiffies = jiffies64_to_cputime64(get_jiffies_64()); 330 cur_jiffies = jiffies64_to_cputime64(get_jiffies_64());
239 total_ticks = (unsigned int) cputime64_sub(cur_jiffies, 331 total_ticks = (unsigned int) cputime64_sub(cur_jiffies,
@@ -274,11 +366,18 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
274 /* Check for frequency increase */ 366 /* Check for frequency increase */
275 if (load > dbs_tuners_ins.up_threshold) { 367 if (load > dbs_tuners_ins.up_threshold) {
276 /* if we are already at full speed then break out early */ 368 /* if we are already at full speed then break out early */
277 if (policy->cur == policy->max) 369 if (!dbs_tuners_ins.powersave_bias) {
278 return; 370 if (policy->cur == policy->max)
279 371 return;
280 __cpufreq_driver_target(policy, policy->max, 372
281 CPUFREQ_RELATION_H); 373 __cpufreq_driver_target(policy, policy->max,
374 CPUFREQ_RELATION_H);
375 } else {
376 int freq = powersave_bias_target(policy, policy->max,
377 CPUFREQ_RELATION_H);
378 __cpufreq_driver_target(policy, freq,
379 CPUFREQ_RELATION_L);
380 }
282 return; 381 return;
283 } 382 }
284 383
@@ -293,14 +392,23 @@ static void dbs_check_cpu(struct cpu_dbs_info_s *this_dbs_info)
293 * policy. To be safe, we focus 10 points under the threshold. 392 * policy. To be safe, we focus 10 points under the threshold.
294 */ 393 */
295 if (load < (dbs_tuners_ins.up_threshold - 10)) { 394 if (load < (dbs_tuners_ins.up_threshold - 10)) {
296 unsigned int freq_next; 395 unsigned int freq_next = (policy->cur * load) /
297 freq_next = (policy->cur * load) /
298 (dbs_tuners_ins.up_threshold - 10); 396 (dbs_tuners_ins.up_threshold - 10);
299 397 if (!dbs_tuners_ins.powersave_bias) {
300 __cpufreq_driver_target(policy, freq_next, CPUFREQ_RELATION_L); 398 __cpufreq_driver_target(policy, freq_next,
399 CPUFREQ_RELATION_L);
400 } else {
401 int freq = powersave_bias_target(policy, freq_next,
402 CPUFREQ_RELATION_L);
403 __cpufreq_driver_target(policy, freq,
404 CPUFREQ_RELATION_L);
405 }
301 } 406 }
302} 407}
303 408
409/* Sampling types */
410enum {DBS_NORMAL_SAMPLE, DBS_SUB_SAMPLE};
411
304static void do_dbs_timer(void *data) 412static void do_dbs_timer(void *data)
305{ 413{
306 unsigned int cpu = smp_processor_id(); 414 unsigned int cpu = smp_processor_id();
@@ -311,10 +419,24 @@ static void do_dbs_timer(void *data)
311 419
312 if (!dbs_info->enable) 420 if (!dbs_info->enable)
313 return; 421 return;
314 422 /* Common NORMAL_SAMPLE setup */
315 lock_cpu_hotplug(); 423 INIT_WORK(&dbs_info->work, do_dbs_timer, (void *)DBS_NORMAL_SAMPLE);
316 dbs_check_cpu(dbs_info); 424 if (!dbs_tuners_ins.powersave_bias ||
317 unlock_cpu_hotplug(); 425 (unsigned long) data == DBS_NORMAL_SAMPLE) {
426 lock_cpu_hotplug();
427 dbs_check_cpu(dbs_info);
428 unlock_cpu_hotplug();
429 if (dbs_info->freq_lo) {
430 /* Setup timer for SUB_SAMPLE */
431 INIT_WORK(&dbs_info->work, do_dbs_timer,
432 (void *)DBS_SUB_SAMPLE);
433 delay = dbs_info->freq_hi_jiffies;
434 }
435 } else {
436 __cpufreq_driver_target(dbs_info->cur_policy,
437 dbs_info->freq_lo,
438 CPUFREQ_RELATION_H);
439 }
318 queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay); 440 queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay);
319} 441}
320 442
@@ -325,6 +447,7 @@ static inline void dbs_timer_init(unsigned int cpu)
325 int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate); 447 int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
326 delay -= jiffies % delay; 448 delay -= jiffies % delay;
327 449
450 ondemand_powersave_bias_init();
328 INIT_WORK(&dbs_info->work, do_dbs_timer, 0); 451 INIT_WORK(&dbs_info->work, do_dbs_timer, 0);
329 queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay); 452 queue_delayed_work_on(cpu, kondemand_wq, &dbs_info->work, delay);
330} 453}