Commit 2c2a83d3 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

Merge back earlier cpuidle material for v5.5.

parents 31d85140 159e4856
...@@ -233,7 +233,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -233,7 +233,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
{ {
struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu); struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
int latency_req = cpuidle_governor_latency_req(dev->cpu); int latency_req = cpuidle_governor_latency_req(dev->cpu);
unsigned int duration_us, count; unsigned int duration_us, hits, misses, early_hits;
int max_early_idx, constraint_idx, idx, i; int max_early_idx, constraint_idx, idx, i;
ktime_t delta_tick; ktime_t delta_tick;
...@@ -247,7 +247,9 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -247,7 +247,9 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
cpu_data->sleep_length_ns = tick_nohz_get_sleep_length(&delta_tick); cpu_data->sleep_length_ns = tick_nohz_get_sleep_length(&delta_tick);
duration_us = ktime_to_us(cpu_data->sleep_length_ns); duration_us = ktime_to_us(cpu_data->sleep_length_ns);
count = 0; hits = 0;
misses = 0;
early_hits = 0;
max_early_idx = -1; max_early_idx = -1;
constraint_idx = drv->state_count; constraint_idx = drv->state_count;
idx = -1; idx = -1;
...@@ -258,23 +260,61 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -258,23 +260,61 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
if (s->disabled || su->disable) { if (s->disabled || su->disable) {
/* /*
* If the "early hits" metric of a disabled state is * Ignore disabled states with target residencies beyond
* greater than the current maximum, it should be taken * the anticipated idle duration.
* into account, because it would be a mistake to select
* a deeper state with lower "early hits" metric. The
* index cannot be changed to point to it, however, so
* just increase the max count alone and let the index
* still point to a shallower idle state.
*/ */
if (max_early_idx >= 0 && if (s->target_residency > duration_us)
count < cpu_data->states[i].early_hits) continue;
count = cpu_data->states[i].early_hits;
/*
* This state is disabled, so the range of idle duration
* values corresponding to it is covered by the current
* candidate state, but still the "hits" and "misses"
* metrics of the disabled state need to be used to
* decide whether or not the state covering the range in
* question is good enough.
*/
hits = cpu_data->states[i].hits;
misses = cpu_data->states[i].misses;
if (early_hits >= cpu_data->states[i].early_hits ||
idx < 0)
continue;
/*
* If the current candidate state has been the one with
* the maximum "early hits" metric so far, the "early
* hits" metric of the disabled state replaces the
* current "early hits" count to avoid selecting a
* deeper state with lower "early hits" metric.
*/
if (max_early_idx == idx) {
early_hits = cpu_data->states[i].early_hits;
continue;
}
/*
* The current candidate state is closer to the disabled
* one than the current maximum "early hits" state, so
* replace the latter with it, but in case the maximum
* "early hits" state index has not been set so far,
* check if the current candidate state is not too
* shallow for that role.
*/
if (!(tick_nohz_tick_stopped() &&
drv->states[idx].target_residency < TICK_USEC)) {
early_hits = cpu_data->states[i].early_hits;
max_early_idx = idx;
}
continue; continue;
} }
if (idx < 0) if (idx < 0) {
idx = i; /* first enabled state */ idx = i; /* first enabled state */
hits = cpu_data->states[i].hits;
misses = cpu_data->states[i].misses;
}
if (s->target_residency > duration_us) if (s->target_residency > duration_us)
break; break;
...@@ -283,11 +323,13 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -283,11 +323,13 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
constraint_idx = i; constraint_idx = i;
idx = i; idx = i;
hits = cpu_data->states[i].hits;
misses = cpu_data->states[i].misses;
if (count < cpu_data->states[i].early_hits && if (early_hits < cpu_data->states[i].early_hits &&
!(tick_nohz_tick_stopped() && !(tick_nohz_tick_stopped() &&
drv->states[i].target_residency < TICK_USEC)) { drv->states[i].target_residency < TICK_USEC)) {
count = cpu_data->states[i].early_hits; early_hits = cpu_data->states[i].early_hits;
max_early_idx = i; max_early_idx = i;
} }
} }
...@@ -300,8 +342,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -300,8 +342,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
* "early hits" metric, but if that cannot be determined, just use the * "early hits" metric, but if that cannot be determined, just use the
* state selected so far. * state selected so far.
*/ */
if (cpu_data->states[idx].hits <= cpu_data->states[idx].misses && if (hits <= misses && max_early_idx >= 0) {
max_early_idx >= 0) {
idx = max_early_idx; idx = max_early_idx;
duration_us = drv->states[idx].target_residency; duration_us = drv->states[idx].target_residency;
} }
...@@ -316,10 +357,9 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev, ...@@ -316,10 +357,9 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
if (idx < 0) { if (idx < 0) {
idx = 0; /* No states enabled. Must use 0. */ idx = 0; /* No states enabled. Must use 0. */
} else if (idx > 0) { } else if (idx > 0) {
unsigned int count = 0;
u64 sum = 0; u64 sum = 0;
count = 0;
/* /*
* Count and sum the most recent idle duration values less than * Count and sum the most recent idle duration values less than
* the current expected idle duration value. * the current expected idle duration value.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment