summaryrefslogtreecommitdiff
path: root/drivers/cpufreq
diff options
context:
space:
mode:
authorsatya popuri <spopuri@nvidia.com>2012-03-09 10:57:31 -0800
committerRohan Somvanshi <rsomvanshi@nvidia.com>2012-03-15 08:45:00 -0700
commitc8c6328fac300f8b93cb61c99e8280981692fa56 (patch)
treeba635a2cac5acfc811d1de6be65f35f473cf1b0d /drivers/cpufreq
parent5bfda21810b190dd50185e839d9a4b650e5fa8f1 (diff)
cpufreq: Add a knob to treat IO wait as busy
The new sysfs node io_is_busy enables the interactive governor to account any time spent by the CPU waiting for IO as non-idle time. This helps us improve run-time of IO bound tasks by making up for lost IO time in speeding up the CPU bound parts of the task. Reviewed on http://git-master/r/#change,86894 cherry picked from 13a15aadc1134b5dae05cdcf9687396644f87411 Signed-off-by: satya popuri <spopuri@nvidia.com> Change-Id: I4a14ed7fef5fbce00054bb02d52d2d3e0f011f70 Reviewed-on: http://git-master/r/89218 Reviewed-by: Satya Popuri <spopuri@nvidia.com> Tested-by: Satya Popuri <spopuri@nvidia.com> Reviewed-by: Automatic_Commit_Validation_User Reviewed-by: Diwakar Tundlam <dtundlam@nvidia.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r--drivers/cpufreq/cpufreq_interactive.c70
1 files changed, 68 insertions, 2 deletions
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c
index 5b7770c78583..5d15e375ec0c 100644
--- a/drivers/cpufreq/cpufreq_interactive.c
+++ b/drivers/cpufreq/cpufreq_interactive.c
@@ -35,11 +35,13 @@ struct cpufreq_interactive_cpuinfo {
struct timer_list cpu_timer;
int timer_idlecancel;
u64 time_in_idle;
+ u64 time_in_iowait;
u64 idle_exit_time;
u64 timer_run_time;
int idling;
u64 freq_change_time;
u64 freq_change_time_in_idle;
+ u64 freq_change_time_in_iowait;
struct cpufreq_policy *policy;
struct cpufreq_frequency_table *freq_table;
unsigned int target_freq;
@@ -68,6 +70,9 @@ static unsigned long boost_factor;
/* Max frequency boost in Hz; if 0 - no max is enforced */
static unsigned long max_boost;
+/* Consider IO as busy */
+static unsigned long io_is_busy;
+
/*
* Targeted sustainable load relatively to current frequency.
* If 0, target is set realtively to the max speed
@@ -132,17 +137,31 @@ static unsigned int cpufreq_interactive_get_target(
return target_freq;
}
+static inline cputime64_t get_cpu_iowait_time(
+ unsigned int cpu, cputime64_t *wall)
+{
+ u64 iowait_time = get_cpu_iowait_time_us(cpu, wall);
+
+ if (iowait_time == -1ULL)
+ return 0;
+
+ return iowait_time;
+}
+
static void cpufreq_interactive_timer(unsigned long data)
{
unsigned int delta_idle;
+ unsigned int delta_iowait;
unsigned int delta_time;
int cpu_load;
int load_since_change;
u64 time_in_idle;
+ u64 time_in_iowait;
u64 idle_exit_time;
struct cpufreq_interactive_cpuinfo *pcpu =
&per_cpu(cpuinfo, data);
u64 now_idle;
+ u64 now_iowait;
unsigned int new_freq;
unsigned int index;
unsigned long flags;
@@ -162,8 +181,10 @@ static void cpufreq_interactive_timer(unsigned long data)
* until more time passes).
*/
time_in_idle = pcpu->time_in_idle;
+ time_in_iowait = pcpu->time_in_iowait;
idle_exit_time = pcpu->idle_exit_time;
now_idle = get_cpu_idle_time_us(data, &pcpu->timer_run_time);
+ now_iowait = get_cpu_iowait_time(data, NULL);
smp_wmb();
/* If we raced with cancelling a timer, skip. */
@@ -171,6 +192,7 @@ static void cpufreq_interactive_timer(unsigned long data)
goto exit;
delta_idle = (unsigned int) cputime64_sub(now_idle, time_in_idle);
+ delta_iowait = (unsigned int) cputime64_sub(now_iowait, time_in_iowait);
delta_time = (unsigned int) cputime64_sub(pcpu->timer_run_time,
idle_exit_time);
@@ -182,19 +204,29 @@ static void cpufreq_interactive_timer(unsigned long data)
if (delta_idle > delta_time)
cpu_load = 0;
- else
+ else {
+ if (io_is_busy && delta_idle >= delta_iowait)
+ delta_idle -= delta_iowait;
+
cpu_load = 100 * (delta_time - delta_idle) / delta_time;
+ }
delta_idle = (unsigned int) cputime64_sub(now_idle,
pcpu->freq_change_time_in_idle);
+ delta_iowait = (unsigned int) cputime64_sub(now_iowait,
+ pcpu->freq_change_time_in_iowait);
delta_time = (unsigned int) cputime64_sub(pcpu->timer_run_time,
pcpu->freq_change_time);
if ((delta_time == 0) || (delta_idle > delta_time))
load_since_change = 0;
- else
+ else {
+ if (io_is_busy && delta_idle >= delta_iowait)
+ delta_idle -= delta_iowait;
+
load_since_change =
100 * (delta_time - delta_idle) / delta_time;
+ }
/*
* Combine short-term load (since last idle timer started or timer
@@ -267,6 +299,9 @@ rearm:
pcpu->time_in_idle = get_cpu_idle_time_us(
data, &pcpu->idle_exit_time);
+ pcpu->time_in_iowait = get_cpu_iowait_time(
+ data, NULL);
+
mod_timer(&pcpu->cpu_timer,
jiffies + usecs_to_jiffies(timer_rate));
}
@@ -301,6 +336,8 @@ static void cpufreq_interactive_idle_start(void)
if (!pending) {
pcpu->time_in_idle = get_cpu_idle_time_us(
smp_processor_id(), &pcpu->idle_exit_time);
+ pcpu->time_in_iowait = get_cpu_iowait_time(
+ smp_processor_id(), NULL);
pcpu->timer_idlecancel = 0;
mod_timer(&pcpu->cpu_timer,
jiffies + usecs_to_jiffies(timer_rate));
@@ -352,6 +389,9 @@ static void cpufreq_interactive_idle_end(void)
pcpu->time_in_idle =
get_cpu_idle_time_us(smp_processor_id(),
&pcpu->idle_exit_time);
+ pcpu->time_in_iowait =
+ get_cpu_iowait_time(smp_processor_id(),
+ NULL);
pcpu->timer_idlecancel = 0;
mod_timer(&pcpu->cpu_timer,
jiffies + usecs_to_jiffies(timer_rate));
@@ -414,6 +454,8 @@ static int cpufreq_interactive_up_task(void *data)
pcpu->freq_change_time_in_idle =
get_cpu_idle_time_us(cpu,
&pcpu->freq_change_time);
+ pcpu->freq_change_time_in_iowait =
+ get_cpu_iowait_time(cpu, NULL);
}
}
@@ -460,6 +502,8 @@ static void cpufreq_interactive_freq_down(struct work_struct *work)
pcpu->freq_change_time_in_idle =
get_cpu_idle_time_us(cpu,
&pcpu->freq_change_time);
+ pcpu->freq_change_time_in_iowait =
+ get_cpu_iowait_time(cpu, NULL);
}
}
@@ -507,6 +551,23 @@ static ssize_t store_boost_factor(struct kobject *kobj,
static struct global_attr boost_factor_attr = __ATTR(boost_factor, 0644,
show_boost_factor, store_boost_factor);
+static ssize_t show_io_is_busy(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ return sprintf(buf, "%lu\n", io_is_busy);
+}
+
+static ssize_t store_io_is_busy(struct kobject *kobj,
+ struct attribute *attr, const char *buf, size_t count)
+{
+ if (!strict_strtoul(buf, 0, &io_is_busy))
+ return count;
+ return -EINVAL;
+}
+
+static struct global_attr io_is_busy_attr = __ATTR(io_is_busy, 0644,
+ show_io_is_busy, store_io_is_busy);
+
static ssize_t show_max_boost(struct kobject *kobj,
struct attribute *attr, char *buf)
{
@@ -600,6 +661,7 @@ static struct attribute *interactive_attributes[] = {
&go_maxspeed_load_attr.attr,
&boost_factor_attr.attr,
&max_boost_attr.attr,
+ &io_is_busy_attr.attr,
&sustain_load_attr.attr,
&min_sample_time_attr.attr,
&timer_rate_attr.attr,
@@ -637,6 +699,10 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
&pcpu->freq_change_time);
pcpu->time_in_idle = pcpu->freq_change_time_in_idle;
pcpu->idle_exit_time = pcpu->freq_change_time;
+ pcpu->freq_change_time_in_iowait =
+ get_cpu_iowait_time(j, NULL);
+ pcpu->time_in_iowait = pcpu->freq_change_time_in_iowait;
+
pcpu->timer_idlecancel = 1;
pcpu->governor_enabled = 1;
smp_wmb();