BACKPORT: cpuidle: teo: Take negative "sleep length" values into account

Modify the TEO governor to take possible negative return values of
tick_nohz_get_next_hrtimer() into account by changing the data type
of some variables used by it to s64 which allows it to carry out
computations without potentially problematic data type conversions
into u64.

Also change the computations in teo_select() so that the negative
values themselves are handled in a natural way to avoid adding extra
negative value checks to that function.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
[ Tashar02: Backport to k4.19 and change data type from unsigned int to int to allow negative values ]
Co-authored-by: Tashfin Shakeer Rhythm <tashfinshakeerrhythm@gmail.com>
Signed-off-by: Tashfin Shakeer Rhythm <tashfinshakeerrhythm@gmail.com>
Signed-off-by: Cyber Knight <cyberknight755@gmail.com>
Signed-off-by: Richard Raya <rdxzv.dev@gmail.com>
This commit is contained in:
Rafael J. Wysocki 2021-03-29 20:21:43 +02:00 committed by Richard Raya
parent 2b14c54cef
commit ccbfc28eb3

View File

@ -101,8 +101,8 @@ struct teo_idle_state {
* @intervals: Saved idle duration values.
*/
struct teo_cpu {
u64 time_span_ns;
u64 sleep_length_ns;
s64 time_span_ns;
s64 sleep_length_ns;
struct teo_idle_state states[CPUIDLE_STATE_MAX];
int last_state;
int interval_idx;
@ -217,7 +217,7 @@ static bool teo_time_ok(unsigned int interval_us)
*/
static int teo_find_shallower_state(struct cpuidle_driver *drv,
struct cpuidle_device *dev, int state_idx,
unsigned int duration_us)
int duration_us)
{
int i;
@ -243,8 +243,8 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
{
struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
int latency_req = cpuidle_governor_latency_req(dev->cpu);
unsigned int duration_us, hits, misses, early_hits;
int max_early_idx, prev_max_early_idx, constraint_idx, idx, i;
int duration_us, max_early_idx, prev_max_early_idx, constraint_idx, idx0, idx, i;
unsigned int hits, misses, early_hits;
ktime_t delta_tick;
if (cpu_data->last_state >= 0) {
@ -264,6 +264,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
prev_max_early_idx = -1;
constraint_idx = drv->state_count;
idx = -1;
idx0 = idx;
for (i = 0; i < drv->state_count; i++) {
struct cpuidle_state *s = &drv->states[i];
@ -324,6 +325,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
idx = i; /* first enabled state */
hits = cpu_data->states[i].hits;
misses = cpu_data->states[i].misses;
idx0 = i;
}
if (s->target_residency > duration_us)
@ -376,11 +378,16 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
if (idx < 0) {
idx = 0; /* No states enabled. Must use 0. */
} else if (idx > 0) {
} else if (idx > idx0) {
unsigned int count = 0;
u64 sum = 0;
/*
* The target residencies of at least two different enabled idle
* states are less than or equal to the current expected idle
* duration. Try to refine the selection using the most recent
* measured idle duration values.
*
* Count and sum the most recent idle duration values less than
* the current expected idle duration value.
*/
@ -430,7 +437,8 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
* till the closest timer including the tick, try to correct
* that.
*/
if (idx > 0 && drv->states[idx].target_residency > delta_tick_us)
if (idx > idx0 &&
drv->states[idx].target_residency > delta_tick_us)
idx = teo_find_shallower_state(drv, dev, idx, delta_tick_us);
}