cpuidle: teo: Avoid stopping the tick unnecessarily when bailing out
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 31 Jul 2023 19:03:09 +0000 (21:03 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Thu, 3 Aug 2023 20:37:03 +0000 (22:37 +0200)
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.

In particular, never stop the tick if state 0 is to be returned.

Link: https://lore.kernel.org/linux-pm/CAJZ5v0jJxHj65r2HXBTd3wfbZtsg=_StzwO1kA5STDnaPe_dWA@mail.gmail.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-and-tested-by: Kajetan Puchalski <kajetan.puchalski@arm.com>
drivers/cpuidle/governors/teo.c

index 2cdc711..1b76db3 100644 (file)
@@ -382,12 +382,13 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
        /* Check if there is any choice in the first place. */
        if (drv->state_count < 2) {
                idx = 0;
-               goto end;
+               goto out_tick;
        }
+
        if (!dev->states_usage[0].disable) {
                idx = 0;
                if (drv->states[1].target_residency_ns > duration_ns)
-                       goto end;
+                       goto out_tick;
        }
 
        cpu_data->utilized = teo_cpu_is_utilized(dev->cpu, cpu_data);
@@ -408,11 +409,12 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
                 * anyway.
                 */
                if ((!idx && !(drv->states[0].flags & CPUIDLE_FLAG_POLLING) &&
-                   teo_time_ok(duration_ns)) || dev->states_usage[1].disable)
+                   teo_time_ok(duration_ns)) || dev->states_usage[1].disable) {
                        idx = 0;
-               else /* Assume that state 1 is not a polling one and use it. */
-                       idx = 1;
-
+                       goto out_tick;
+               }
+               /* Assume that state 1 is not a polling one and use it. */
+               idx = 1;
                goto end;
        }
 
@@ -459,8 +461,15 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
        /* Avoid unnecessary overhead. */
        if (idx < 0) {
                idx = 0; /* No states enabled, must use 0. */
-               goto end;
-       } else if (idx == idx0) {
+               goto out_tick;
+       }
+
+       if (idx == idx0) {
+               /*
+                * This is the first enabled idle state, so use it, but do not
+                * allow the tick to be stopped it is shallow enough.
+                */
+               duration_ns = drv->states[idx].target_residency_ns;
                goto end;
        }
 
@@ -566,24 +575,25 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
 
 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);
-       }
+       /*
+        * 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);
 
+out_tick:
+       *stop_tick = false;
        return idx;
 }