Skip to content

Commit b54df61

Browse files
committed
cpuidle: governors: teo: Decay metrics below DECAY_SHIFT threshold
If a given governor metric falls below a certain value (8 for DECAY_SHIFT equal to 3), it will not decay any more due to the simplistic decay implementation. This may in some cases lead to subtle inconsistencies in the governor behavior, so change the decay implementation to take it into account and set the metric at hand to 0 in that case. Suggested-by: Christian Loehle <christian.loehle@arm.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Reviewed-by: Christian Loehle <christian.loehle@arm.com> Tested-by: Christian Loehle <christian.loehle@arm.com> Link: https://patch.msgid.link/2819353.mvXUDI8C0e@rafael.j.wysocki
1 parent 8f3f010 commit b54df61

1 file changed

Lines changed: 19 additions & 7 deletions

File tree

  • drivers/cpuidle/governors

drivers/cpuidle/governors/teo.c

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,16 @@ struct teo_cpu {
148148

149149
static DEFINE_PER_CPU(struct teo_cpu, teo_cpus);
150150

151+
static void teo_decay(unsigned int *metric)
152+
{
153+
unsigned int delta = *metric >> DECAY_SHIFT;
154+
155+
if (delta)
156+
*metric -= delta;
157+
else
158+
*metric = 0;
159+
}
160+
151161
/**
152162
* teo_update - Update CPU metrics after wakeup.
153163
* @drv: cpuidle driver containing state data.
@@ -158,8 +168,9 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
158168
struct teo_cpu *cpu_data = this_cpu_ptr(&teo_cpus);
159169
int i, idx_timer = 0, idx_duration = 0;
160170
s64 target_residency_ns, measured_ns;
171+
unsigned int total = 0;
161172

162-
cpu_data->short_idles -= cpu_data->short_idles >> DECAY_SHIFT;
173+
teo_decay(&cpu_data->short_idles);
163174

164175
if (cpu_data->artificial_wakeup) {
165176
/*
@@ -195,8 +206,10 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
195206
for (i = 0; i < drv->state_count; i++) {
196207
struct teo_bin *bin = &cpu_data->state_bins[i];
197208

198-
bin->hits -= bin->hits >> DECAY_SHIFT;
199-
bin->intercepts -= bin->intercepts >> DECAY_SHIFT;
209+
teo_decay(&bin->hits);
210+
total += bin->hits;
211+
teo_decay(&bin->intercepts);
212+
total += bin->intercepts;
200213

201214
target_residency_ns = drv->states[i].target_residency_ns;
202215

@@ -207,7 +220,9 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
207220
}
208221
}
209222

210-
cpu_data->tick_intercepts -= cpu_data->tick_intercepts >> DECAY_SHIFT;
223+
cpu_data->total = total + PULSE;
224+
225+
teo_decay(&cpu_data->tick_intercepts);
211226
/*
212227
* If the measured idle duration falls into the same bin as the sleep
213228
* length, this is a "hit", so update the "hits" metric for that bin.
@@ -221,9 +236,6 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
221236
if (TICK_NSEC <= measured_ns)
222237
cpu_data->tick_intercepts += PULSE;
223238
}
224-
225-
cpu_data->total -= cpu_data->total >> DECAY_SHIFT;
226-
cpu_data->total += PULSE;
227239
}
228240

229241
static bool teo_state_ok(int i, struct cpuidle_driver *drv)

0 commit comments

Comments
 (0)