cpufreq: governors: Calculate iowait time only when necessary

Currently we always calculate the CPU iowait time and add it to idle time.
If we are in ondemand and we use io_is_busy, we re-calculate iowait time
and we subtract it from idle time.

With this patch iowait time is calculated only when necessary avoiding
the double call to get_cpu_iowait_time_us. We use a parameter in
function get_cpu_idle_time to distinguish when the iowait time will be
added to idle time or not, without the need of keeping the prev_io_wait.

Signed-off-by: Stratos Karafotis <stratosk@semaphore.gr>
Acked-by: Viresh Kumar <viresh.kumar@linaro.,org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
This commit is contained in:
Stratos Karafotis 2013-02-28 16:57:32 +00:00 committed by Rafael J. Wysocki
parent fed573d5c9
commit 9366d84052
4 changed files with 30 additions and 34 deletions

View File

@ -240,7 +240,7 @@ static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
struct cs_cpu_dbs_info_s *dbs_info; struct cs_cpu_dbs_info_s *dbs_info;
dbs_info = &per_cpu(cs_cpu_dbs_info, j); dbs_info = &per_cpu(cs_cpu_dbs_info, j);
dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j, dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
&dbs_info->cdbs.prev_cpu_wall); &dbs_info->cdbs.prev_cpu_wall, 0);
if (cs_tuners->ignore_nice) if (cs_tuners->ignore_nice)
dbs_info->cdbs.prev_cpu_nice = dbs_info->cdbs.prev_cpu_nice =
kcpustat_cpu(j).cpustat[CPUTIME_NICE]; kcpustat_cpu(j).cpustat[CPUTIME_NICE];

View File

@ -67,13 +67,13 @@ static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
return cputime_to_usecs(idle_time); return cputime_to_usecs(idle_time);
} }
u64 get_cpu_idle_time(unsigned int cpu, u64 *wall) u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy)
{ {
u64 idle_time = get_cpu_idle_time_us(cpu, NULL); u64 idle_time = get_cpu_idle_time_us(cpu, io_busy ? wall : NULL);
if (idle_time == -1ULL) if (idle_time == -1ULL)
return get_cpu_idle_time_jiffy(cpu, wall); return get_cpu_idle_time_jiffy(cpu, wall);
else else if (!io_busy)
idle_time += get_cpu_iowait_time_us(cpu, wall); idle_time += get_cpu_iowait_time_us(cpu, wall);
return idle_time; return idle_time;
@ -100,13 +100,22 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
/* Get Absolute Load (in terms of freq for ondemand gov) */ /* Get Absolute Load (in terms of freq for ondemand gov) */
for_each_cpu(j, policy->cpus) { for_each_cpu(j, policy->cpus) {
struct cpu_dbs_common_info *j_cdbs; struct cpu_dbs_common_info *j_cdbs;
u64 cur_wall_time, cur_idle_time, cur_iowait_time; u64 cur_wall_time, cur_idle_time;
unsigned int idle_time, wall_time, iowait_time; unsigned int idle_time, wall_time;
unsigned int load; unsigned int load;
int io_busy = 0;
j_cdbs = dbs_data->cdata->get_cpu_cdbs(j); j_cdbs = dbs_data->cdata->get_cpu_cdbs(j);
cur_idle_time = get_cpu_idle_time(j, &cur_wall_time); /*
* For the purpose of ondemand, waiting for disk IO is
* an indication that you're performance critical, and
* not that the system is actually idle. So do not add
* the iowait time to the cpu idle time.
*/
if (dbs_data->cdata->governor == GOV_ONDEMAND)
io_busy = od_tuners->io_is_busy;
cur_idle_time = get_cpu_idle_time(j, &cur_wall_time, io_busy);
wall_time = (unsigned int) wall_time = (unsigned int)
(cur_wall_time - j_cdbs->prev_cpu_wall); (cur_wall_time - j_cdbs->prev_cpu_wall);
@ -134,29 +143,6 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu)
idle_time += jiffies_to_usecs(cur_nice_jiffies); idle_time += jiffies_to_usecs(cur_nice_jiffies);
} }
if (dbs_data->cdata->governor == GOV_ONDEMAND) {
struct od_cpu_dbs_info_s *od_j_dbs_info =
dbs_data->cdata->get_cpu_dbs_info_s(cpu);
cur_iowait_time = get_cpu_iowait_time_us(j,
&cur_wall_time);
if (cur_iowait_time == -1ULL)
cur_iowait_time = 0;
iowait_time = (unsigned int) (cur_iowait_time -
od_j_dbs_info->prev_cpu_iowait);
od_j_dbs_info->prev_cpu_iowait = cur_iowait_time;
/*
* For the purpose of ondemand, waiting for disk IO is
* an indication that you're performance critical, and
* not that the system is actually idle. So subtract the
* iowait time from the cpu idle time.
*/
if (od_tuners->io_is_busy && idle_time >= iowait_time)
idle_time -= iowait_time;
}
if (unlikely(!wall_time || wall_time < idle_time)) if (unlikely(!wall_time || wall_time < idle_time))
continue; continue;
@ -254,6 +240,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
struct cs_dbs_tuners *cs_tuners = NULL; struct cs_dbs_tuners *cs_tuners = NULL;
struct cpu_dbs_common_info *cpu_cdbs; struct cpu_dbs_common_info *cpu_cdbs;
unsigned int sampling_rate, latency, ignore_nice, j, cpu = policy->cpu; unsigned int sampling_rate, latency, ignore_nice, j, cpu = policy->cpu;
int io_busy = 0;
int rc; int rc;
if (have_governor_per_policy()) if (have_governor_per_policy())
@ -353,6 +340,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
sampling_rate = od_tuners->sampling_rate; sampling_rate = od_tuners->sampling_rate;
ignore_nice = od_tuners->ignore_nice; ignore_nice = od_tuners->ignore_nice;
od_ops = dbs_data->cdata->gov_ops; od_ops = dbs_data->cdata->gov_ops;
io_busy = od_tuners->io_is_busy;
} }
switch (event) { switch (event) {
@ -369,7 +357,7 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy,
j_cdbs->cpu = j; j_cdbs->cpu = j;
j_cdbs->cur_policy = policy; j_cdbs->cur_policy = policy;
j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, j_cdbs->prev_cpu_idle = get_cpu_idle_time(j,
&j_cdbs->prev_cpu_wall); &j_cdbs->prev_cpu_wall, io_busy);
if (ignore_nice) if (ignore_nice)
j_cdbs->prev_cpu_nice = j_cdbs->prev_cpu_nice =
kcpustat_cpu(j).cpustat[CPUTIME_NICE]; kcpustat_cpu(j).cpustat[CPUTIME_NICE];

View File

@ -148,7 +148,6 @@ struct cpu_dbs_common_info {
struct od_cpu_dbs_info_s { struct od_cpu_dbs_info_s {
struct cpu_dbs_common_info cdbs; struct cpu_dbs_common_info cdbs;
u64 prev_cpu_iowait;
struct cpufreq_frequency_table *freq_table; struct cpufreq_frequency_table *freq_table;
unsigned int freq_lo; unsigned int freq_lo;
unsigned int freq_lo_jiffies; unsigned int freq_lo_jiffies;
@ -256,7 +255,7 @@ static ssize_t show_sampling_rate_min_gov_pol \
return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \ return sprintf(buf, "%u\n", dbs_data->min_sampling_rate); \
} }
u64 get_cpu_idle_time(unsigned int cpu, u64 *wall); u64 get_cpu_idle_time(unsigned int cpu, u64 *wall, int io_busy);
void dbs_check_cpu(struct dbs_data *dbs_data, int cpu); void dbs_check_cpu(struct dbs_data *dbs_data, int cpu);
bool need_load_eval(struct cpu_dbs_common_info *cdbs, bool need_load_eval(struct cpu_dbs_common_info *cdbs,
unsigned int sampling_rate); unsigned int sampling_rate);

View File

@ -339,11 +339,20 @@ static ssize_t store_io_is_busy(struct dbs_data *dbs_data, const char *buf,
struct od_dbs_tuners *od_tuners = dbs_data->tuners; struct od_dbs_tuners *od_tuners = dbs_data->tuners;
unsigned int input; unsigned int input;
int ret; int ret;
unsigned int j;
ret = sscanf(buf, "%u", &input); ret = sscanf(buf, "%u", &input);
if (ret != 1) if (ret != 1)
return -EINVAL; return -EINVAL;
od_tuners->io_is_busy = !!input; od_tuners->io_is_busy = !!input;
/* we need to re-evaluate prev_cpu_idle */
for_each_online_cpu(j) {
struct od_cpu_dbs_info_s *dbs_info = &per_cpu(od_cpu_dbs_info,
j);
dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
&dbs_info->cdbs.prev_cpu_wall, od_tuners->io_is_busy);
}
return count; return count;
} }
@ -414,7 +423,7 @@ static ssize_t store_ignore_nice(struct dbs_data *dbs_data, const char *buf,
struct od_cpu_dbs_info_s *dbs_info; struct od_cpu_dbs_info_s *dbs_info;
dbs_info = &per_cpu(od_cpu_dbs_info, j); dbs_info = &per_cpu(od_cpu_dbs_info, j);
dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j, dbs_info->cdbs.prev_cpu_idle = get_cpu_idle_time(j,
&dbs_info->cdbs.prev_cpu_wall); &dbs_info->cdbs.prev_cpu_wall, od_tuners->io_is_busy);
if (od_tuners->ignore_nice) if (od_tuners->ignore_nice)
dbs_info->cdbs.prev_cpu_nice = dbs_info->cdbs.prev_cpu_nice =
kcpustat_cpu(j).cpustat[CPUTIME_NICE]; kcpustat_cpu(j).cpustat[CPUTIME_NICE];