public inbox for stable@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH 6.12.y 0/6] cpuidle: menu: Backport get_typical_interval() improvements
@ 2026-03-20 20:29 Ionut Nechita
  2026-03-20 20:29 ` [PATCH 6.12.y 1/6] cpuidle: menu: Drop a redundant local variable Ionut Nechita
                   ` (5 more replies)
  0 siblings, 6 replies; 8+ messages in thread
From: Ionut Nechita @ 2026-03-20 20:29 UTC (permalink / raw)
  To: stable
  Cc: rafael.j.wysocki, linux-pm, christian.loehle, artem.bityutskiy,
	quic_zhonhan, aboorvad, Ionut Nechita

From: Ionut Nechita <ionut_n2001@yahoo.com>

This series backports 6 upstream commits that improve the menu
governor's get_typical_interval() function to linux-6.12.y stable.

These patches are already present in linux-6.18.y but were not picked
up for 6.12.y because they lack Cc: stable tags.

The key improvement is in patch 2/6 which merges the two separate loops
for average and variance computation into a single pass, reducing the
latency of menu_select() on isolated (nohz_full) cores. The remaining
patches refactor outlier detection to cover both ends of the sample set,
update documentation to match the new code, and add a minor bucket
assignment optimization.

After applying this series, drivers/cpuidle/governors/menu.c matches
linux-6.18.y exactly.

All patches are clean cherry-picks from mainline with one trivial
conflict resolution in Documentation/admin-guide/pm/cpuidle.rst
(patch 5/6).

Upstream commits:
  d2cd195b57cf ("cpuidle: menu: Drop a redundant local variable")
  13982929fb08 ("cpuidle: menu: Use one loop for average and variance computations")
  60256e458e1c ("cpuidle: menu: Tweak threshold use in get_typical_interval()")
  8de7606f0fe2 ("cpuidle: menu: Eliminate outliers on both ends of the sample set")
  5c35041099965 ("cpuidle: menu: Update documentation after get_typical_interval() changes")
  d4a7882f93bf ("cpuidle: menu: Optimize bucket assignment when next_timer_ns equals KTIME_MAX")

Rafael J. Wysocki (5):
  cpuidle: menu: Drop a redundant local variable
  cpuidle: menu: Use one loop for average and variance computations
  cpuidle: menu: Tweak threshold use in get_typical_interval()
  cpuidle: menu: Eliminate outliers on both ends of the sample set
  cpuidle: menu: Update documentation after get_typical_interval()
    changes

Zhongqiu Han (1):
  cpuidle: menu: Optimize bucket assignment when next_timer_ns equals
    KTIME_MAX

 Documentation/admin-guide/pm/cpuidle.rst |  56 +++++++----
 drivers/cpuidle/governors/menu.c         | 118 +++++++++++------------
 2 files changed, 91 insertions(+), 83 deletions(-)

--
2.53.0


^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 6.12.y 1/6] cpuidle: menu: Drop a redundant local variable
  2026-03-20 20:29 [PATCH 6.12.y 0/6] cpuidle: menu: Backport get_typical_interval() improvements Ionut Nechita
@ 2026-03-20 20:29 ` Ionut Nechita
  2026-03-21  8:24   ` Greg KH
  2026-03-20 20:29 ` [PATCH 6.12.y 2/6] cpuidle: menu: Use one loop for average and variance computations Ionut Nechita
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 8+ messages in thread
From: Ionut Nechita @ 2026-03-20 20:29 UTC (permalink / raw)
  To: stable
  Cc: rafael.j.wysocki, linux-pm, christian.loehle, artem.bityutskiy,
	quic_zhonhan, aboorvad

From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>

Local variable min in get_typical_interval() is updated, but never
accessed later, so drop it.

No functional impact.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Christian Loehle <christian.loehle@arm.com>
Tested-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Tested-by: Christian Loehle <christian.loehle@arm.com>
Tested-by: Aboorva Devarajan <aboorvad@linux.ibm.com>
Link: https://patch.msgid.link/13699686.uLZWGnKmhe@rjwysocki.net
---
 drivers/cpuidle/governors/menu.c | 6 +-----
 1 file changed, 1 insertion(+), 5 deletions(-)

diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 0ce7323450011..dd7e2a965878e 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -125,7 +125,7 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev);
 static unsigned int get_typical_interval(struct menu_device *data)
 {
 	int i, divisor;
-	unsigned int min, max, thresh, avg;
+	unsigned int max, thresh, avg;
 	uint64_t sum, variance;
 
 	thresh = INT_MAX; /* Discard outliers above this value */
@@ -133,7 +133,6 @@ static unsigned int get_typical_interval(struct menu_device *data)
 again:
 
 	/* First calculate the average of past intervals */
-	min = UINT_MAX;
 	max = 0;
 	sum = 0;
 	divisor = 0;
@@ -144,9 +143,6 @@ static unsigned int get_typical_interval(struct menu_device *data)
 			divisor++;
 			if (value > max)
 				max = value;
-
-			if (value < min)
-				min = value;
 		}
 	}
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 6.12.y 2/6] cpuidle: menu: Use one loop for average and variance computations
  2026-03-20 20:29 [PATCH 6.12.y 0/6] cpuidle: menu: Backport get_typical_interval() improvements Ionut Nechita
  2026-03-20 20:29 ` [PATCH 6.12.y 1/6] cpuidle: menu: Drop a redundant local variable Ionut Nechita
@ 2026-03-20 20:29 ` Ionut Nechita
  2026-03-20 20:29 ` [PATCH 6.12.y 3/6] cpuidle: menu: Tweak threshold use in get_typical_interval() Ionut Nechita
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Ionut Nechita @ 2026-03-20 20:29 UTC (permalink / raw)
  To: stable
  Cc: rafael.j.wysocki, linux-pm, christian.loehle, artem.bityutskiy,
	quic_zhonhan, aboorvad

From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>

Use the observation that one loop is sufficient to compute the average
of an array of values and their variance to eliminate one of the loops
from get_typical_interval().

While at it, make get_typical_interval() consistently use u64 as the
64-bit unsigned integer data type and rearrange some white space and the
declarations of local variables in it (to make them follow the reverse
X-mas tree pattern).

No intentional functional impact.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Reviewed-by: Christian Loehle <christian.loehle@arm.com>
Tested-by: Christian Loehle <christian.loehle@arm.com>
Tested-by: Aboorva Devarajan <aboorvad@linux.ibm.com>
Link: https://patch.msgid.link/3339073.aeNJFYEL58@rjwysocki.net
---
 drivers/cpuidle/governors/menu.c | 61 +++++++++++++++-----------------
 1 file changed, 28 insertions(+), 33 deletions(-)

diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index dd7e2a965878e..8943bb8f19190 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -124,49 +124,45 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev);
  */
 static unsigned int get_typical_interval(struct menu_device *data)
 {
-	int i, divisor;
-	unsigned int max, thresh, avg;
-	uint64_t sum, variance;
-
-	thresh = INT_MAX; /* Discard outliers above this value */
+	unsigned int max, divisor, thresh = INT_MAX;
+	u64 avg, variance, avg_sq;
+	int i;
 
 again:
-
-	/* First calculate the average of past intervals */
+	/* Compute the average and variance of past intervals. */
 	max = 0;
-	sum = 0;
+	avg = 0;
+	variance = 0;
 	divisor = 0;
 	for (i = 0; i < INTERVALS; i++) {
 		unsigned int value = data->intervals[i];
-		if (value <= thresh) {
-			sum += value;
-			divisor++;
-			if (value > max)
-				max = value;
-		}
+
+		/* Discard data points above the threshold. */
+		if (value > thresh)
+			continue;
+
+		divisor++;
+
+		avg += value;
+		variance += (u64)value * value;
+
+		if (value > max)
+			max = value;
 	}
 
 	if (!max)
 		return UINT_MAX;
 
-	if (divisor == INTERVALS)
-		avg = sum >> INTERVAL_SHIFT;
-	else
-		avg = div_u64(sum, divisor);
-
-	/* Then try to determine variance */
-	variance = 0;
-	for (i = 0; i < INTERVALS; i++) {
-		unsigned int value = data->intervals[i];
-		if (value <= thresh) {
-			int64_t diff = (int64_t)value - avg;
-			variance += diff * diff;
-		}
-	}
-	if (divisor == INTERVALS)
+	if (divisor == INTERVALS) {
+		avg >>= INTERVAL_SHIFT;
 		variance >>= INTERVAL_SHIFT;
-	else
+	} else {
+		do_div(avg, divisor);
 		do_div(variance, divisor);
+	}
+
+	avg_sq = avg * avg;
+	variance -= avg_sq;
 
 	/*
 	 * The typical interval is obtained when standard deviation is
@@ -181,10 +177,9 @@ static unsigned int get_typical_interval(struct menu_device *data)
 	 * Use this result only if there is no timer to wake us up sooner.
 	 */
 	if (likely(variance <= U64_MAX/36)) {
-		if ((((u64)avg*avg > variance*36) && (divisor * 4 >= INTERVALS * 3))
-							|| variance <= 400) {
+		if ((avg_sq > variance * 36 && divisor * 4 >= INTERVALS * 3) ||
+		    variance <= 400)
 			return avg;
-		}
 	}
 
 	/*
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 6.12.y 3/6] cpuidle: menu: Tweak threshold use in get_typical_interval()
  2026-03-20 20:29 [PATCH 6.12.y 0/6] cpuidle: menu: Backport get_typical_interval() improvements Ionut Nechita
  2026-03-20 20:29 ` [PATCH 6.12.y 1/6] cpuidle: menu: Drop a redundant local variable Ionut Nechita
  2026-03-20 20:29 ` [PATCH 6.12.y 2/6] cpuidle: menu: Use one loop for average and variance computations Ionut Nechita
@ 2026-03-20 20:29 ` Ionut Nechita
  2026-03-20 20:29 ` [PATCH 6.12.y 4/6] cpuidle: menu: Eliminate outliers on both ends of the sample set Ionut Nechita
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 8+ messages in thread
From: Ionut Nechita @ 2026-03-20 20:29 UTC (permalink / raw)
  To: stable
  Cc: rafael.j.wysocki, linux-pm, christian.loehle, artem.bityutskiy,
	quic_zhonhan, aboorvad

From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>

To prepare get_typical_interval() for subsequent changes, rearrange
the use of the data point threshold in it a bit and initialize that
threshold to UINT_MAX which is more consistent with its data type.

No intentional functional impact.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Tested-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Reviewed-by: Christian Loehle <christian.loehle@arm.com>
Tested-by: Christian Loehle <christian.loehle@arm.com>
Tested-by: Aboorva Devarajan <aboorvad@linux.ibm.com>
Link: https://patch.msgid.link/8490144.T7Z3S40VBb@rjwysocki.net
---
 drivers/cpuidle/governors/menu.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 8943bb8f19190..96bee77b8354f 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -124,7 +124,7 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev);
  */
 static unsigned int get_typical_interval(struct menu_device *data)
 {
-	unsigned int max, divisor, thresh = INT_MAX;
+	unsigned int max, divisor, thresh = UINT_MAX;
 	u64 avg, variance, avg_sq;
 	int i;
 
@@ -137,8 +137,8 @@ static unsigned int get_typical_interval(struct menu_device *data)
 	for (i = 0; i < INTERVALS; i++) {
 		unsigned int value = data->intervals[i];
 
-		/* Discard data points above the threshold. */
-		if (value > thresh)
+		/* Discard data points above or at the threshold. */
+		if (value >= thresh)
 			continue;
 
 		divisor++;
@@ -202,7 +202,7 @@ static unsigned int get_typical_interval(struct menu_device *data)
 	if (divisor * 4 <= INTERVALS * 3)
 		return UINT_MAX;
 
-	thresh = max - 1;
+	thresh = max;
 	goto again;
 }
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 6.12.y 4/6] cpuidle: menu: Eliminate outliers on both ends of the sample set
  2026-03-20 20:29 [PATCH 6.12.y 0/6] cpuidle: menu: Backport get_typical_interval() improvements Ionut Nechita
                   ` (2 preceding siblings ...)
  2026-03-20 20:29 ` [PATCH 6.12.y 3/6] cpuidle: menu: Tweak threshold use in get_typical_interval() Ionut Nechita
@ 2026-03-20 20:29 ` Ionut Nechita
  2026-03-20 20:29 ` [PATCH 6.12.y 5/6] cpuidle: menu: Update documentation after get_typical_interval() changes Ionut Nechita
  2026-03-20 20:29 ` [PATCH 6.12.y 6/6] cpuidle: menu: Optimize bucket assignment when next_timer_ns equals KTIME_MAX Ionut Nechita
  5 siblings, 0 replies; 8+ messages in thread
From: Ionut Nechita @ 2026-03-20 20:29 UTC (permalink / raw)
  To: stable
  Cc: rafael.j.wysocki, linux-pm, christian.loehle, artem.bityutskiy,
	quic_zhonhan, aboorvad

From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>

Currently, get_typical_interval() attempts to eliminate outliers at the
high end of the sample set only (probably in order to bias the prediction
toward lower values), but this it problematic because if the outliers are
present at the low end of the sample set, discarding the highest values
will not help to reduce the variance.

Since the presence of outliers at the low end of the sample set is
generally as likely as their presence at the high end of the sample
set, modify get_typical_interval() to treat samples at the largest
distances from the average (on both ends of the sample set) as outliers.

This should increase the likelihood of making a meaningful prediction
in some cases.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reported-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Tested-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
Reviewed-by: Christian Loehle <christian.loehle@arm.com>
Tested-by: Christian Loehle <christian.loehle@arm.com>
Tested-by: Aboorva Devarajan <aboorvad@linux.ibm.com>
Link: https://patch.msgid.link/2301940.iZASKD2KPV@rjwysocki.net
---
 drivers/cpuidle/governors/menu.c | 32 ++++++++++++++++++++++----------
 1 file changed, 22 insertions(+), 10 deletions(-)

diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 96bee77b8354f..8ab5123c81040 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -124,30 +124,37 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev);
  */
 static unsigned int get_typical_interval(struct menu_device *data)
 {
-	unsigned int max, divisor, thresh = UINT_MAX;
+	s64 value, min_thresh = -1, max_thresh = UINT_MAX;
+	unsigned int max, min, divisor;
 	u64 avg, variance, avg_sq;
 	int i;
 
 again:
 	/* Compute the average and variance of past intervals. */
 	max = 0;
+	min = UINT_MAX;
 	avg = 0;
 	variance = 0;
 	divisor = 0;
 	for (i = 0; i < INTERVALS; i++) {
-		unsigned int value = data->intervals[i];
-
-		/* Discard data points above or at the threshold. */
-		if (value >= thresh)
+		value = data->intervals[i];
+		/*
+		 * Discard the samples outside the interval between the min and
+		 * max thresholds.
+		 */
+		if (value <= min_thresh || value >= max_thresh)
 			continue;
 
 		divisor++;
 
 		avg += value;
-		variance += (u64)value * value;
+		variance += value * value;
 
 		if (value > max)
 			max = value;
+
+		if (value < min)
+			min = value;
 	}
 
 	if (!max)
@@ -183,10 +190,10 @@ static unsigned int get_typical_interval(struct menu_device *data)
 	}
 
 	/*
-	 * If we have outliers to the upside in our distribution, discard
-	 * those by setting the threshold to exclude these outliers, then
+	 * If there are outliers, discard them by setting thresholds to exclude
+	 * data points at a large enough distance from the average, then
 	 * calculate the average and standard deviation again. Once we get
-	 * down to the bottom 3/4 of our samples, stop excluding samples.
+	 * down to the last 3/4 of our samples, stop excluding samples.
 	 *
 	 * This can deal with workloads that have long pauses interspersed
 	 * with sporadic activity with a bunch of short pauses.
@@ -202,7 +209,12 @@ static unsigned int get_typical_interval(struct menu_device *data)
 	if (divisor * 4 <= INTERVALS * 3)
 		return UINT_MAX;
 
-	thresh = max;
+	/* Update the thresholds for the next round. */
+	if (avg - min > max - avg)
+		min_thresh = min;
+	else
+		max_thresh = max;
+
 	goto again;
 }
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 6.12.y 5/6] cpuidle: menu: Update documentation after get_typical_interval() changes
  2026-03-20 20:29 [PATCH 6.12.y 0/6] cpuidle: menu: Backport get_typical_interval() improvements Ionut Nechita
                   ` (3 preceding siblings ...)
  2026-03-20 20:29 ` [PATCH 6.12.y 4/6] cpuidle: menu: Eliminate outliers on both ends of the sample set Ionut Nechita
@ 2026-03-20 20:29 ` Ionut Nechita
  2026-03-20 20:29 ` [PATCH 6.12.y 6/6] cpuidle: menu: Optimize bucket assignment when next_timer_ns equals KTIME_MAX Ionut Nechita
  5 siblings, 0 replies; 8+ messages in thread
From: Ionut Nechita @ 2026-03-20 20:29 UTC (permalink / raw)
  To: stable
  Cc: rafael.j.wysocki, linux-pm, christian.loehle, artem.bityutskiy,
	quic_zhonhan, aboorvad

From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>

The documentation of the menu cpuidle governor needs to be updated
to match the code behavior after some changes made recently.

No functional impact.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Christian Loehle <christian.loehle@arm.com>
Link: https://patch.msgid.link/4998484.31r3eYUQgx@rjwysocki.net
[ rjw: More specific subject, two typos fixed in the changelog ]
---
 Documentation/admin-guide/pm/cpuidle.rst | 56 +++++++++++++++---------
 drivers/cpuidle/governors/menu.c         | 29 +++++-------
 2 files changed, 45 insertions(+), 40 deletions(-)

diff --git a/Documentation/admin-guide/pm/cpuidle.rst b/Documentation/admin-guide/pm/cpuidle.rst
index 19754beb5a4e6..9fcc35498fb0e 100644
--- a/Documentation/admin-guide/pm/cpuidle.rst
+++ b/Documentation/admin-guide/pm/cpuidle.rst
@@ -295,30 +295,44 @@ values and, when predicting the idle duration next time, it computes the average
 and variance of them.  If the variance is small (smaller than 400 square
 milliseconds) or it is small relative to the average (the average is greater
 that 6 times the standard deviation), the average is regarded as the "typical
-interval" value.  Otherwise, the longest of the saved observed idle duration
+interval" value.  Otherwise, either the longest or the shortest (depending on
+which one is farther from the average) of the saved observed idle duration
 values is discarded and the computation is repeated for the remaining ones.
+
 Again, if the variance of them is small (in the above sense), the average is
 taken as the "typical interval" value and so on, until either the "typical
-interval" is determined or too many data points are disregarded, in which case
-the "typical interval" is assumed to equal "infinity" (the maximum unsigned
-integer value).  The "typical interval" computed this way is compared with the
-sleep length multiplied by the correction factor and the minimum of the two is
-taken as the predicted idle duration.
-
-Then, the governor computes an extra latency limit to help "interactive"
-workloads.  It uses the observation that if the exit latency of the selected
-idle state is comparable with the predicted idle duration, the total time spent
-in that state probably will be very short and the amount of energy to save by
-entering it will be relatively small, so likely it is better to avoid the
-overhead related to entering that state and exiting it.  Thus selecting a
-shallower state is likely to be a better option then.   The first approximation
-of the extra latency limit is the predicted idle duration itself which
-additionally is divided by a value depending on the number of tasks that
-previously ran on the given CPU and now they are waiting for I/O operations to
-complete.  The result of that division is compared with the latency limit coming
-from the power management quality of service, or `PM QoS <cpu-pm-qos_>`_,
-framework and the minimum of the two is taken as the limit for the idle states'
-exit latency.
+interval" is determined or too many data points are disregarded.  In the latter
+case, if the size of the set of data points still under consideration is
+sufficiently large, the next idle duration is not likely to be above the largest
+idle duration value still in that set, so that value is taken as the predicted
+next idle duration.  Finally, if the set of data points still under
+consideration is too small, no prediction is made.
+
+If the preliminary prediction of the next idle duration computed this way is
+long enough, the governor obtains the time until the closest timer event with
+the assumption that the scheduler tick will be stopped.  That time, referred to
+as the *sleep length* in what follows, is the upper bound on the time before the
+next CPU wakeup.  It is used to determine the sleep length range, which in turn
+is needed to get the sleep length correction factor.
+
+The ``menu`` governor maintains an array containing several correction factor
+values that correspond to different sleep length ranges organized so that each
+range represented in the array is approximately 10 times wider than the previous
+one.
+
+The correction factor for the given sleep length range (determined before
+selecting the idle state for the CPU) is updated after the CPU has been woken
+up and the closer the sleep length is to the observed idle duration, the closer
+to 1 the correction factor becomes (it must fall between 0 and 1 inclusive).
+The sleep length is multiplied by the correction factor for the range that it
+falls into to obtain an approximation of the predicted idle duration that is
+compared to the "typical interval" determined previously and the minimum of
+the two is taken as the final idle duration prediction.
+
+If the "typical interval" value is small, which means that the CPU is likely
+to be woken up soon enough, the sleep length computation is skipped as it may
+be costly and the idle duration is simply predicted to equal the "typical
+interval" value.
 
 Now, the governor is ready to walk the list of idle states and choose one of
 them.  For this purpose, it compares the target residency of each state with
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 8ab5123c81040..a18477ecce433 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -41,7 +41,7 @@
  * the  C state is required to actually break even on this cost. CPUIDLE
  * provides us this duration in the "target_residency" field. So all that we
  * need is a good prediction of how long we'll be idle. Like the traditional
- * menu governor, we start with the actual known "next timer event" time.
+ * menu governor, we take the actual known "next timer event" time.
  *
  * Since there are other source of wakeups (interrupts for example) than
  * the next timer event, this estimation is rather optimistic. To get a
@@ -50,30 +50,21 @@
  * duration always was 50% of the next timer tick, the correction factor will
  * be 0.5.
  *
- * menu uses a running average for this correction factor, however it uses a
- * set of factors, not just a single factor. This stems from the realization
- * that the ratio is dependent on the order of magnitude of the expected
- * duration; if we expect 500 milliseconds of idle time the likelihood of
- * getting an interrupt very early is much higher than if we expect 50 micro
- * seconds of idle time. A second independent factor that has big impact on
- * the actual factor is if there is (disk) IO outstanding or not.
- * (as a special twist, we consider every sleep longer than 50 milliseconds
- * as perfect; there are no power gains for sleeping longer than this)
- *
- * For these two reasons we keep an array of 12 independent factors, that gets
- * indexed based on the magnitude of the expected duration as well as the
- * "is IO outstanding" property.
+ * menu uses a running average for this correction factor, but it uses a set of
+ * factors, not just a single factor. This stems from the realization that the
+ * ratio is dependent on the order of magnitude of the expected duration; if we
+ * expect 500 milliseconds of idle time the likelihood of getting an interrupt
+ * very early is much higher than if we expect 50 micro seconds of idle time.
+ * For this reason, menu keeps an array of 6 independent factors, that gets
+ * indexed based on the magnitude of the expected duration.
  *
  * Repeatable-interval-detector
  * ----------------------------
  * There are some cases where "next timer" is a completely unusable predictor:
  * Those cases where the interval is fixed, for example due to hardware
- * interrupt mitigation, but also due to fixed transfer rate devices such as
- * mice.
+ * interrupt mitigation, but also due to fixed transfer rate devices like mice.
  * For this, we use a different predictor: We track the duration of the last 8
- * intervals and if the stand deviation of these 8 intervals is below a
- * threshold value, we use the average of these intervals as prediction.
- *
+ * intervals and use them to estimate the duration of the next one.
  */
 
 struct menu_device {
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 6.12.y 6/6] cpuidle: menu: Optimize bucket assignment when next_timer_ns equals KTIME_MAX
  2026-03-20 20:29 [PATCH 6.12.y 0/6] cpuidle: menu: Backport get_typical_interval() improvements Ionut Nechita
                   ` (4 preceding siblings ...)
  2026-03-20 20:29 ` [PATCH 6.12.y 5/6] cpuidle: menu: Update documentation after get_typical_interval() changes Ionut Nechita
@ 2026-03-20 20:29 ` Ionut Nechita
  5 siblings, 0 replies; 8+ messages in thread
From: Ionut Nechita @ 2026-03-20 20:29 UTC (permalink / raw)
  To: stable
  Cc: rafael.j.wysocki, linux-pm, christian.loehle, artem.bityutskiy,
	quic_zhonhan, aboorvad

From: Zhongqiu Han <quic_zhonhan@quicinc.com>

Directly assign the last bucket value instead of calling which_bucket()
when next_timer_ns equals KTIME_MAX, the largest possible value that
always falls into the last bucket.

This avoids unnecessary calculations and enhances performance.

Reviewed-by: Christian Loehle <christian.loehle@arm.com>
Signed-off-by: Zhongqiu Han <quic_zhonhan@quicinc.com>
Link: https://patch.msgid.link/20250405135308.1854342-1-quic_zhonhan@quicinc.com
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
---
 drivers/cpuidle/governors/menu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index a18477ecce433..ca863ba03d454 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -278,7 +278,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
 		 */
 		data->next_timer_ns = KTIME_MAX;
 		delta_tick = TICK_NSEC / 2;
-		data->bucket = which_bucket(KTIME_MAX);
+		data->bucket = BUCKETS - 1;
 	}
 
 	if (unlikely(drv->state_count <= 1 || latency_req == 0) ||
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH 6.12.y 1/6] cpuidle: menu: Drop a redundant local variable
  2026-03-20 20:29 ` [PATCH 6.12.y 1/6] cpuidle: menu: Drop a redundant local variable Ionut Nechita
@ 2026-03-21  8:24   ` Greg KH
  0 siblings, 0 replies; 8+ messages in thread
From: Greg KH @ 2026-03-21  8:24 UTC (permalink / raw)
  To: Ionut Nechita
  Cc: stable, rafael.j.wysocki, linux-pm, christian.loehle,
	artem.bityutskiy, quic_zhonhan, aboorvad

On Fri, Mar 20, 2026 at 10:29:03PM +0200, Ionut Nechita wrote:
> From: "Rafael J. Wysocki" <rafael.j.wysocki@intel.com>
> 
> Local variable min in get_typical_interval() is updated, but never
> accessed later, so drop it.
> 
> No functional impact.
> 
> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
> Reviewed-by: Christian Loehle <christian.loehle@arm.com>
> Tested-by: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
> Tested-by: Christian Loehle <christian.loehle@arm.com>
> Tested-by: Aboorva Devarajan <aboorvad@linux.ibm.com>
> Link: https://patch.msgid.link/13699686.uLZWGnKmhe@rjwysocki.net
> ---
>  drivers/cpuidle/governors/menu.c | 6 +-----
>  1 file changed, 1 insertion(+), 5 deletions(-)

Again, you forgot the original git id.  Please redo the series with that
information.

And you all know this, I went through "how to properly backport patches
to stable" a lot with your team, this needs to be reviewed by someone
else at windriver before it can be accepted as you also messed up on
something else here that you should have gotten correct :(

thanks,

greg k-h

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-03-21  8:24 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-20 20:29 [PATCH 6.12.y 0/6] cpuidle: menu: Backport get_typical_interval() improvements Ionut Nechita
2026-03-20 20:29 ` [PATCH 6.12.y 1/6] cpuidle: menu: Drop a redundant local variable Ionut Nechita
2026-03-21  8:24   ` Greg KH
2026-03-20 20:29 ` [PATCH 6.12.y 2/6] cpuidle: menu: Use one loop for average and variance computations Ionut Nechita
2026-03-20 20:29 ` [PATCH 6.12.y 3/6] cpuidle: menu: Tweak threshold use in get_typical_interval() Ionut Nechita
2026-03-20 20:29 ` [PATCH 6.12.y 4/6] cpuidle: menu: Eliminate outliers on both ends of the sample set Ionut Nechita
2026-03-20 20:29 ` [PATCH 6.12.y 5/6] cpuidle: menu: Update documentation after get_typical_interval() changes Ionut Nechita
2026-03-20 20:29 ` [PATCH 6.12.y 6/6] cpuidle: menu: Optimize bucket assignment when next_timer_ns equals KTIME_MAX Ionut Nechita

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox