* [PATCH v2 0/3] cpuidle: teo: Avoid stopping scheduler tick too often
@ 2023-07-28 9:35 Rafael J. Wysocki
2023-07-28 9:58 ` [PATCH v2 1/3] cpuidle: teo: Update idle duration estimate when choosing shallower state Rafael J. Wysocki
` (2 more replies)
0 siblings, 3 replies; 4+ messages in thread
From: Rafael J. Wysocki @ 2023-07-28 9:35 UTC (permalink / raw)
To: Linux PM
Cc: LKML, Peter Zijlstra, Anna-Maria Behnsen, Frederic Weisbecker,
Kajetan Puchalski
Hi Folks,
Patch [1/3] in this series is a v2 of this patch posted yesterday:
https://lore.kernel.org/linux-pm/4506480.LvFx2qVVIh@kreacher/
Patch [2/3] addresses some bail out paths in teo_select() in which the
scheduler tick may be stopped unnecessarily too.
Patch [3/3] replaces a structure field with a local variable (while at it).
Thanks!
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 1/3] cpuidle: teo: Update idle duration estimate when choosing shallower state
2023-07-28 9:35 [PATCH v2 0/3] cpuidle: teo: Avoid stopping scheduler tick too often Rafael J. Wysocki
@ 2023-07-28 9:58 ` Rafael J. Wysocki
2023-07-28 10:00 ` [PATCH v2 2/3] cpuidle: teo: Avoid stopping the tick unnecessarily when bailing out Rafael J. Wysocki
2023-07-28 10:01 ` [PATCH v2 3/3] cpuidle: teo: Drop utilized from struct teo_cpu Rafael J. Wysocki
2 siblings, 0 replies; 4+ messages in thread
From: Rafael J. Wysocki @ 2023-07-28 9:58 UTC (permalink / raw)
To: Linux PM
Cc: LKML, Peter Zijlstra, Anna-Maria Behnsen, Frederic Weisbecker,
Kajetan Puchalski
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
The TEO governor takes CPU utilization into account by refining idle state
selection when the utilization is above a certain threshold. This is done by
choosing an idle state shallower than the previously selected one.
However, when doing this, the idle duration estimate needs to be
adjusted so as to prevent the scheduler tick from being stopped when the
candidate idle state is shallow, which may lead to excessive energy
usage if the CPU is not woken up quickly enough going forward.
Moreover, if the scheduler tick has been stopped already and the new
idle duration estimate is too small, the replacement candidate state
cannot be used.
Modify the relevant code to take the above observations into account.
Fixes: 9ce0f7c4bc64 ("cpuidle: teo: Introduce util-awareness")
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
v1 -> v2:
* Rework the code handling the special case when the CPU is utilized and
there are only 2 idle states (drop the loop, avoid using state 0 when
the tick has been stopped already and it is too shallow, check if
state 1 is not disabled when about to use it, set low idle duration
estimate).
* Changelog edits.
---
drivers/cpuidle/governors/teo.c | 43 ++++++++++++++++++++++++++++++----------
1 file changed, 33 insertions(+), 10 deletions(-)
Index: linux-pm/drivers/cpuidle/governors/teo.c
===================================================================
--- linux-pm.orig/drivers/cpuidle/governors/teo.c
+++ linux-pm/drivers/cpuidle/governors/teo.c
@@ -397,13 +397,26 @@ static int teo_select(struct cpuidle_dri
* the shallowest non-polling state and exit.
*/
if (drv->state_count < 3 && cpu_data->utilized) {
- for (i = 0; i < drv->state_count; ++i) {
- if (!dev->states_usage[i].disable &&
- !(drv->states[i].flags & CPUIDLE_FLAG_POLLING)) {
- idx = i;
- goto end;
- }
- }
+ /* The CPU is utilized, so assume a short idle duration. */
+ duration_ns = teo_middle_of_bin(0, drv);
+ /*
+ * If state 0 is enabled and it is not a polling one, select it
+ * right away unless the scheduler tick has been stopped, in
+ * which case care needs to be taken to leave the CPU in a
+ * deep enough state in case it is not woken up any time soon
+ * after all.
+ */
+ if (!idx && !(drv->states[0].flags & CPUIDLE_FLAG_POLLING) &&
+ teo_time_ok(duration_ns))
+ goto end;
+
+ /*
+ * Assume that state 1 is not a polling one and select it
+ * unless it is disabled, in which case state 0 must be used
+ * no matter what.
+ */
+ idx = dev->states_usage[1].disable ? 0 : 1;
+ goto end;
}
/*
@@ -539,10 +552,20 @@ static int teo_select(struct cpuidle_dri
/*
* If the CPU is being utilized over the threshold, choose a shallower
- * non-polling state to improve latency
+ * non-polling state to improve latency, unless the scheduler tick has
+ * been stopped already and the shallower state's target residency is
+ * not sufficiently large.
*/
- if (cpu_data->utilized)
- idx = teo_find_shallower_state(drv, dev, idx, duration_ns, true);
+ if (cpu_data->utilized) {
+ s64 span_ns;
+
+ i = teo_find_shallower_state(drv, dev, idx, duration_ns, true);
+ span_ns = teo_middle_of_bin(i, drv);
+ if (teo_time_ok(span_ns)) {
+ idx = i;
+ duration_ns = span_ns;
+ }
+ }
end:
/*
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 2/3] cpuidle: teo: Avoid stopping the tick unnecessarily when bailing out
2023-07-28 9:35 [PATCH v2 0/3] cpuidle: teo: Avoid stopping scheduler tick too often Rafael J. Wysocki
2023-07-28 9:58 ` [PATCH v2 1/3] cpuidle: teo: Update idle duration estimate when choosing shallower state Rafael J. Wysocki
@ 2023-07-28 10:00 ` Rafael J. Wysocki
2023-07-28 10:01 ` [PATCH v2 3/3] cpuidle: teo: Drop utilized from struct teo_cpu Rafael J. Wysocki
2 siblings, 0 replies; 4+ messages in thread
From: Rafael J. Wysocki @ 2023-07-28 10:00 UTC (permalink / raw)
To: Linux PM
Cc: LKML, Peter Zijlstra, Anna-Maria Behnsen, Frederic Weisbecker,
Kajetan Puchalski
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
When teo_select() is going to return early in some special cases, make
it avoid stopping the tick if the idle state to be returned is shallow.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/cpuidle/governors/teo.c | 50 +++++++++++++++++++++++++---------------
1 file changed, 32 insertions(+), 18 deletions(-)
Index: linux-pm/drivers/cpuidle/governors/teo.c
===================================================================
--- linux-pm.orig/drivers/cpuidle/governors/teo.c
+++ linux-pm/drivers/cpuidle/governors/teo.c
@@ -462,9 +462,9 @@ static int teo_select(struct cpuidle_dri
/* Avoid unnecessary overhead. */
if (idx < 0) {
idx = 0; /* No states enabled, must use 0. */
- goto end;
+ goto bail_out;
} else if (idx == idx0) {
- goto end;
+ goto bail_out;
}
/*
@@ -547,8 +547,10 @@ static int teo_select(struct cpuidle_dri
* If there is a latency constraint, it may be necessary to select an
* idle state shallower than the current candidate one.
*/
- if (idx > constraint_idx)
+ if (idx > constraint_idx) {
idx = constraint_idx;
+ goto bail_out;
+ }
/*
* If the CPU is being utilized over the threshold, choose a shallower
@@ -569,23 +571,35 @@ static int teo_select(struct cpuidle_dri
end:
/*
- * Don't stop the tick if the selected state is a polling one or if the
- * expected idle duration is shorter than the tick period length.
+ * Allow the tick to be stopped unless the selected state is a polling
+ * one or the expected idle duration is shorter than the tick period
+ * length.
*/
- if (((drv->states[idx].flags & CPUIDLE_FLAG_POLLING) ||
- duration_ns < TICK_NSEC) && !tick_nohz_tick_stopped()) {
- *stop_tick = false;
+ if ((!(drv->states[idx].flags & CPUIDLE_FLAG_POLLING) &&
+ duration_ns >= TICK_NSEC) || tick_nohz_tick_stopped())
+ return idx;
- /*
- * The tick is not going to be stopped, so if the target
- * residency of the state to be returned is not within the time
- * till the closest timer including the tick, try to correct
- * that.
- */
- if (idx > idx0 &&
- drv->states[idx].target_residency_ns > delta_tick)
- idx = teo_find_shallower_state(drv, dev, idx, delta_tick, false);
- }
+retain_tick:
+ *stop_tick = false;
+
+ /*
+ * The tick is not going to be stopped, so if the target residency of
+ * the state to be returned is not within the time till the closest
+ * timer including the tick, try to correct that.
+ */
+ if (idx > idx0 &&
+ drv->states[idx].target_residency_ns > delta_tick)
+ idx = teo_find_shallower_state(drv, dev, idx, delta_tick, false);
+
+ return idx;
+
+bail_out:
+ /*
+ * Do not allow the tick to be stopped if the selected state is shallow
+ * enough.
+ */
+ if (drv->states[idx].target_residency_ns < TICK_NSEC)
+ goto retain_tick;
return idx;
}
^ permalink raw reply [flat|nested] 4+ messages in thread
* [PATCH v2 3/3] cpuidle: teo: Drop utilized from struct teo_cpu
2023-07-28 9:35 [PATCH v2 0/3] cpuidle: teo: Avoid stopping scheduler tick too often Rafael J. Wysocki
2023-07-28 9:58 ` [PATCH v2 1/3] cpuidle: teo: Update idle duration estimate when choosing shallower state Rafael J. Wysocki
2023-07-28 10:00 ` [PATCH v2 2/3] cpuidle: teo: Avoid stopping the tick unnecessarily when bailing out Rafael J. Wysocki
@ 2023-07-28 10:01 ` Rafael J. Wysocki
2 siblings, 0 replies; 4+ messages in thread
From: Rafael J. Wysocki @ 2023-07-28 10:01 UTC (permalink / raw)
To: Linux PM
Cc: LKML, Peter Zijlstra, Anna-Maria Behnsen, Frederic Weisbecker,
Kajetan Puchalski
From: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Because the utilized field in struct teo_cpu is only used locally in
teo_select(), replace it with a local variable in that function.
No intentional functional impact.
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
drivers/cpuidle/governors/teo.c | 9 ++++-----
1 file changed, 4 insertions(+), 5 deletions(-)
Index: linux-pm/drivers/cpuidle/governors/teo.c
===================================================================
--- linux-pm.orig/drivers/cpuidle/governors/teo.c
+++ linux-pm/drivers/cpuidle/governors/teo.c
@@ -187,7 +187,6 @@ struct teo_bin {
* @next_recent_idx: Index of the next @recent_idx entry to update.
* @recent_idx: Indices of bins corresponding to recent "intercepts".
* @util_threshold: Threshold above which the CPU is considered utilized
- * @utilized: Whether the last sleep on the CPU happened while utilized
*/
struct teo_cpu {
s64 time_span_ns;
@@ -197,7 +196,6 @@ struct teo_cpu {
int next_recent_idx;
int recent_idx[NR_RECENT];
unsigned long util_threshold;
- bool utilized;
};
static DEFINE_PER_CPU(struct teo_cpu, teo_cpus);
@@ -366,6 +364,7 @@ static int teo_select(struct cpuidle_dri
int idx0 = 0, idx = -1;
bool alt_intercepts, alt_recent;
ktime_t delta_tick;
+ bool cpu_utilized;
s64 duration_ns;
int i;
@@ -390,13 +389,13 @@ static int teo_select(struct cpuidle_dri
goto end;
}
- cpu_data->utilized = teo_cpu_is_utilized(dev->cpu, cpu_data);
+ cpu_utilized = teo_cpu_is_utilized(dev->cpu, cpu_data);
/*
* If the CPU is being utilized over the threshold and there are only 2
* states to choose from, the metrics need not be considered, so choose
* the shallowest non-polling state and exit.
*/
- if (drv->state_count < 3 && cpu_data->utilized) {
+ if (drv->state_count < 3 && cpu_utilized) {
/* The CPU is utilized, so assume a short idle duration. */
duration_ns = teo_middle_of_bin(0, drv);
/*
@@ -558,7 +557,7 @@ static int teo_select(struct cpuidle_dri
* been stopped already and the shallower state's target residency is
* not sufficiently large.
*/
- if (cpu_data->utilized) {
+ if (cpu_utilized) {
s64 span_ns;
i = teo_find_shallower_state(drv, dev, idx, duration_ns, true);
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2023-07-28 10:02 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-07-28 9:35 [PATCH v2 0/3] cpuidle: teo: Avoid stopping scheduler tick too often Rafael J. Wysocki
2023-07-28 9:58 ` [PATCH v2 1/3] cpuidle: teo: Update idle duration estimate when choosing shallower state Rafael J. Wysocki
2023-07-28 10:00 ` [PATCH v2 2/3] cpuidle: teo: Avoid stopping the tick unnecessarily when bailing out Rafael J. Wysocki
2023-07-28 10:01 ` [PATCH v2 3/3] cpuidle: teo: Drop utilized from struct teo_cpu Rafael J. Wysocki
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).