cpufreq: interactive: add io_is_busy interface
authorLianwei Wang <lian-wei.wang@motorola.com>
Fri, 22 Feb 2013 03:39:18 +0000 (11:39 +0800)
committerJohn Stultz <john.stultz@linaro.org>
Tue, 16 Feb 2016 21:52:53 +0000 (13:52 -0800)
Previously the idle time returned from get_cpu_idle_time_us included the
iowait time. So the iowait time was always calculated as idle time.

But now the idle time returned from get_cpu_idle_time_us does not include
the iowait time anymore because of below commit which cause the iowait time
always calculated as busy time:
    6beea0c nohz: Fix update_ts_time_stat idle accounting

Add the io_is_busy interface, as does the ondemand governor, and let the user
configure the iowait time as busy or idle through the io_is_busy sysfs
interface.

By default, io_is_busy is disabled.

[toddpoynor@google.com: minor updates]
Change-Id: If7d70ff864c43bc9c8d7fd7cfc66f930d339f9b4
Signed-off-by: Lianwei Wang <lian-wei.wang@motorola.com>
Signed-off-by: Todd Poynor <toddpoynor@google.com>
drivers/cpufreq/cpufreq_interactive.c

index 620b46cb94477c68ffd23db17fa26bfa1abe8627..7c734fa57e245fa37b1790bd90f92b36de4a93a5 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/workqueue.h>
 #include <linux/kthread.h>
 #include <linux/slab.h>
 #include <linux/workqueue.h>
 #include <linux/kthread.h>
 #include <linux/slab.h>
+#include <linux/kernel_stat.h>
 #include <asm/cputime.h>
 
 #define CREATE_TRACE_POINTS
 #include <asm/cputime.h>
 
 #define CREATE_TRACE_POINTS
@@ -114,6 +115,8 @@ static u64 boostpulse_endtime;
 #define DEFAULT_TIMER_SLACK (4 * DEFAULT_TIMER_RATE)
 static int timer_slack_val = DEFAULT_TIMER_SLACK;
 
 #define DEFAULT_TIMER_SLACK (4 * DEFAULT_TIMER_RATE)
 static int timer_slack_val = DEFAULT_TIMER_SLACK;
 
+static bool io_is_busy;
+
 static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
                unsigned int event);
 
 static int cpufreq_governor_interactive(struct cpufreq_policy *policy,
                unsigned int event);
 
@@ -127,6 +130,42 @@ struct cpufreq_governor cpufreq_gov_interactive = {
        .owner = THIS_MODULE,
 };
 
        .owner = THIS_MODULE,
 };
 
+static inline cputime64_t get_cpu_idle_time_jiffy(unsigned int cpu,
+                                                 cputime64_t *wall)
+{
+       u64 idle_time;
+       u64 cur_wall_time;
+       u64 busy_time;
+
+       cur_wall_time = jiffies64_to_cputime64(get_jiffies_64());
+
+       busy_time  = kcpustat_cpu(cpu).cpustat[CPUTIME_USER];
+       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SYSTEM];
+       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_IRQ];
+       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_SOFTIRQ];
+       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_STEAL];
+       busy_time += kcpustat_cpu(cpu).cpustat[CPUTIME_NICE];
+
+       idle_time = cur_wall_time - busy_time;
+       if (wall)
+               *wall = jiffies_to_usecs(cur_wall_time);
+
+       return jiffies_to_usecs(idle_time);
+}
+
+static inline cputime64_t get_cpu_idle_time(unsigned int cpu,
+                                           cputime64_t *wall)
+{
+       u64 idle_time = get_cpu_idle_time_us(cpu, wall);
+
+       if (idle_time == -1ULL)
+               idle_time = get_cpu_idle_time_jiffy(cpu, wall);
+       else if (!io_is_busy)
+               idle_time += get_cpu_iowait_time_us(cpu, wall);
+
+       return idle_time;
+}
+
 static void cpufreq_interactive_timer_resched(
        struct cpufreq_interactive_cpuinfo *pcpu)
 {
 static void cpufreq_interactive_timer_resched(
        struct cpufreq_interactive_cpuinfo *pcpu)
 {
@@ -141,7 +180,7 @@ static void cpufreq_interactive_timer_resched(
 
        spin_lock_irqsave(&pcpu->load_lock, flags);
        pcpu->time_in_idle =
 
        spin_lock_irqsave(&pcpu->load_lock, flags);
        pcpu->time_in_idle =
-               get_cpu_idle_time_us(smp_processor_id(),
+               get_cpu_idle_time(smp_processor_id(),
                                     &pcpu->time_in_idle_timestamp);
        pcpu->cputime_speedadj = 0;
        pcpu->cputime_speedadj_timestamp = pcpu->time_in_idle_timestamp;
                                     &pcpu->time_in_idle_timestamp);
        pcpu->cputime_speedadj = 0;
        pcpu->cputime_speedadj_timestamp = pcpu->time_in_idle_timestamp;
@@ -278,7 +317,7 @@ static u64 update_load(int cpu)
        unsigned int delta_time;
        u64 active_time;
 
        unsigned int delta_time;
        u64 active_time;
 
-       now_idle = get_cpu_idle_time_us(cpu, &now);
+       now_idle = get_cpu_idle_time(cpu, &now);
        delta_idle = (unsigned int)(now_idle - pcpu->time_in_idle);
        delta_time = (unsigned int)(now - pcpu->time_in_idle_timestamp);
        active_time = delta_time - delta_idle;
        delta_idle = (unsigned int)(now_idle - pcpu->time_in_idle);
        delta_time = (unsigned int)(now - pcpu->time_in_idle_timestamp);
        active_time = delta_time - delta_idle;
@@ -924,6 +963,28 @@ static ssize_t store_boostpulse_duration(
 
 define_one_global_rw(boostpulse_duration);
 
 
 define_one_global_rw(boostpulse_duration);
 
+static ssize_t show_io_is_busy(struct kobject *kobj,
+                       struct attribute *attr, char *buf)
+{
+       return sprintf(buf, "%u\n", io_is_busy);
+}
+
+static ssize_t store_io_is_busy(struct kobject *kobj,
+                       struct attribute *attr, const char *buf, size_t count)
+{
+       int ret;
+       unsigned long val;
+
+       ret = kstrtoul(buf, 0, &val);
+       if (ret < 0)
+               return ret;
+       io_is_busy = val;
+       return count;
+}
+
+static struct global_attr io_is_busy_attr = __ATTR(io_is_busy, 0644,
+               show_io_is_busy, store_io_is_busy);
+
 static struct attribute *interactive_attributes[] = {
        &target_loads_attr.attr,
        &above_hispeed_delay_attr.attr,
 static struct attribute *interactive_attributes[] = {
        &target_loads_attr.attr,
        &above_hispeed_delay_attr.attr,
@@ -935,6 +996,7 @@ static struct attribute *interactive_attributes[] = {
        &boost.attr,
        &boostpulse.attr,
        &boostpulse_duration.attr,
        &boost.attr,
        &boostpulse.attr,
        &boostpulse_duration.attr,
+       &io_is_busy_attr.attr,
        NULL,
 };
 
        NULL,
 };