diff options
author | satya popuri <spopuri@nvidia.com> | 2012-03-09 10:57:31 -0800 |
---|---|---|
committer | Rohan Somvanshi <rsomvanshi@nvidia.com> | 2012-03-15 08:45:00 -0700 |
commit | c8c6328fac300f8b93cb61c99e8280981692fa56 (patch) | |
tree | ba635a2cac5acfc811d1de6be65f35f473cf1b0d /drivers/cpufreq | |
parent | 5bfda21810b190dd50185e839d9a4b650e5fa8f1 (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.c | 70 |
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(); |