Merge branch 'pm-cpuidle'

Merge cpuidle updates for 6.15-rc5, including a menu governor update
that is reported to improve some benchmark results quite significantly:

 - Update the handling of the most recent idle intervals in the menu
   cpuidle governor to prevent useful information from being discarded
   by it in some cases and improve the prediction accuracy (Rafael
   Wysocki).

 - Make it possible to tell the intel_idle driver to ignore its built-in
   table of idle states for the given processor, clean up the handling
   of auto-demotion disabling on Baytrail and Cherrytrail chips in it,
   and update its MAINTAINERS entry (David Arcari, Artem Bityutskiy,
   Rafael Wysocki).

 - Make some cpuidle drivers use for_each_present_cpu() instead of
   for_each_possible_cpu() during initialization to avoid issues
   occurring when nosmp or maxcpus=0 are used (Jacky Bai).

* pm-cpuidle:
  cpuidle: Init cpuidle only for present CPUs
  cpuidle: intel_idle: Update MAINTAINERS
  intel_idle: introduce 'no_native' module parameter
  cpuidle: menu: Update documentation after get_typical_interval() changes
  cpuidle: menu: Avoid discarding useful information
  cpuidle: menu: Eliminate outliers on both ends of the sample set
  cpuidle: menu: Tweak threshold use in get_typical_interval()
  cpuidle: menu: Use one loop for average and variance computations
  cpuidle: menu: Drop a redundant local variable
  intel_idle: clean up BYT/CHT auto demotion disable
This commit is contained in:
Rafael J. Wysocki
2025-03-24 14:43:30 +01:00
10 changed files with 137 additions and 98 deletions
+16 -11
View File
@@ -275,20 +275,25 @@ 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).
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 "typical interval" 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.
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
@@ -302,7 +307,7 @@ 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 idle duration prediction.
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
+13 -5
View File
@@ -192,11 +192,19 @@ even if they have been enumerated (see :ref:`cpu-pm-qos` in
Documentation/admin-guide/pm/cpuidle.rst).
Setting ``max_cstate`` to 0 causes the ``intel_idle`` initialization to fail.
The ``no_acpi`` and ``use_acpi`` module parameters (recognized by ``intel_idle``
if the kernel has been configured with ACPI support) can be set to make the
driver ignore the system's ACPI tables entirely or use them for all of the
recognized processor models, respectively (they both are unset by default and
``use_acpi`` has no effect if ``no_acpi`` is set).
The ``no_acpi``, ``use_acpi`` and ``no_native`` module parameters are
recognized by ``intel_idle`` if the kernel has been configured with ACPI
support. In the case that ACPI is not configured these flags have no impact
on functionality.
``no_acpi`` - Do not use ACPI at all. Only native mode is available, no
ACPI mode.
``use_acpi`` - No-op in ACPI mode, the driver will consult ACPI tables for
C-states on/off status in native mode.
``no_native`` - Work only in ACPI mode, no native mode available (ignore
all custom tables).
The value of the ``states_off`` module parameter (0 by default) represents a
list of idle states to be disabled by default in the form of a bitmask.
+5 -3
View File
@@ -11675,12 +11675,14 @@ F: Documentation/driver-api/crypto/iaa/iaa-crypto.rst
F: drivers/crypto/intel/iaa/*
INTEL IDLE DRIVER
M: Jacob Pan <jacob.jun.pan@linux.intel.com>
M: Len Brown <lenb@kernel.org>
M: Rafael J. Wysocki <rafael@kernel.org>
M: Artem Bityutskiy <artem.bityutskiy@linux.intel.com>
M: Artem Bityutskiy <dedekind1@gmail.com>
R: Len Brown <lenb@kernel.org>
L: linux-pm@vger.kernel.org
S: Supported
B: https://bugzilla.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/lenb/linux.git
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
F: drivers/idle/intel_idle.c
INTEL IDXD DRIVER
+4 -4
View File
@@ -137,9 +137,9 @@ out_kfree_drv:
/*
* arm_idle_init - Initializes arm cpuidle driver
*
* Initializes arm cpuidle driver for all CPUs, if any CPU fails
* to register cpuidle driver then rollback to cancel all CPUs
* registration.
* Initializes arm cpuidle driver for all present CPUs, if any
* CPU fails to register cpuidle driver then rollback to cancel
* all CPUs registration.
*/
static int __init arm_idle_init(void)
{
@@ -147,7 +147,7 @@ static int __init arm_idle_init(void)
struct cpuidle_driver *drv;
struct cpuidle_device *dev;
for_each_possible_cpu(cpu) {
for_each_present_cpu(cpu) {
ret = arm_idle_init_cpu(cpu);
if (ret)
goto out_fail;
+1 -1
View File
@@ -148,7 +148,7 @@ static int __init bl_idle_driver_init(struct cpuidle_driver *drv, int part_id)
if (!cpumask)
return -ENOMEM;
for_each_possible_cpu(cpu)
for_each_present_cpu(cpu)
if (smp_cpuid_part(cpu) == part_id)
cpumask_set_cpu(cpu, cpumask);
+2 -2
View File
@@ -400,7 +400,7 @@ deinit:
/*
* psci_idle_probe - Initializes PSCI cpuidle driver
*
* Initializes PSCI cpuidle driver for all CPUs, if any CPU fails
* Initializes PSCI cpuidle driver for all present CPUs, if any CPU fails
* to register cpuidle driver then rollback to cancel all CPUs
* registration.
*/
@@ -410,7 +410,7 @@ static int psci_cpuidle_probe(struct platform_device *pdev)
struct cpuidle_driver *drv;
struct cpuidle_device *dev;
for_each_possible_cpu(cpu) {
for_each_present_cpu(cpu) {
ret = psci_idle_init_cpu(&pdev->dev, cpu);
if (ret)
goto out_fail;
+1 -1
View File
@@ -135,7 +135,7 @@ static int spm_cpuidle_drv_probe(struct platform_device *pdev)
if (ret)
return dev_err_probe(&pdev->dev, ret, "set warm boot addr failed");
for_each_possible_cpu(cpu) {
for_each_present_cpu(cpu) {
ret = spm_cpuidle_register(&pdev->dev, cpu);
if (ret && ret != -ENODEV) {
dev_err(&pdev->dev,
+2 -2
View File
@@ -529,8 +529,8 @@ static int sbi_cpuidle_probe(struct platform_device *pdev)
return ret;
}
/* Initialize CPU idle driver for each CPU */
for_each_possible_cpu(cpu) {
/* Initialize CPU idle driver for each present CPU */
for_each_present_cpu(cpu) {
ret = sbi_cpuidle_init_cpu(&pdev->dev, cpu);
if (ret) {
pr_debug("HART%ld: idle driver init failed\n",
+66 -61
View File
@@ -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 {
@@ -116,53 +107,52 @@ 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;
uint64_t sum, variance;
thresh = INT_MAX; /* Discard outliers above this value */
s64 value, min_thresh = -1, max_thresh = UINT_MAX;
unsigned int max, min, divisor;
u64 avg, variance, avg_sq;
int i;
again:
/* First calculate the average of past intervals */
min = UINT_MAX;
/* Compute the average and variance of past intervals. */
max = 0;
sum = 0;
min = UINT_MAX;
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;
value = data->intervals[i];
/*
* Discard the samples outside the interval between the min and
* max thresholds.
*/
if (value <= min_thresh || value >= max_thresh)
continue;
if (value < min)
min = value;
}
divisor++;
avg += value;
variance += value * value;
if (value > max)
max = value;
if (value < min)
min = 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
@@ -177,25 +167,40 @@ again:
* 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;
}
}
/*
* 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.
*/
if ((divisor * 4) <= INTERVALS * 3)
if (divisor * 4 <= INTERVALS * 3) {
/*
* If there are sufficiently many data points still under
* consideration after the outliers have been eliminated,
* returning without a prediction would be a mistake because it
* is likely that the next interval will not exceed the current
* maximum, so return the latter in that case.
*/
if (divisor >= INTERVALS / 2)
return max;
return UINT_MAX;
}
/* Update the thresholds for the next round. */
if (avg - min > max - avg)
min_thresh = min;
else
max_thresh = max;
thresh = max - 1;
goto again;
}
+27 -8
View File
@@ -90,7 +90,6 @@ struct idle_cpu {
* Indicate which enable bits to clear here.
*/
unsigned long auto_demotion_disable_flags;
bool byt_auto_demotion_disable_flag;
bool disable_promotion_to_c1e;
bool use_acpi;
};
@@ -1464,13 +1463,11 @@ static const struct idle_cpu idle_cpu_snx __initconst = {
static const struct idle_cpu idle_cpu_byt __initconst = {
.state_table = byt_cstates,
.disable_promotion_to_c1e = true,
.byt_auto_demotion_disable_flag = true,
};
static const struct idle_cpu idle_cpu_cht __initconst = {
.state_table = cht_cstates,
.disable_promotion_to_c1e = true,
.byt_auto_demotion_disable_flag = true,
};
static const struct idle_cpu idle_cpu_ivb __initconst = {
@@ -1696,6 +1693,10 @@ static bool force_use_acpi __read_mostly; /* No effect if no_acpi is set. */
module_param_named(use_acpi, force_use_acpi, bool, 0444);
MODULE_PARM_DESC(use_acpi, "Use ACPI _CST for building the idle states list");
static bool no_native __read_mostly; /* No effect if no_acpi is set. */
module_param_named(no_native, no_native, bool, 0444);
MODULE_PARM_DESC(no_native, "Ignore cpu specific (native) idle states in lieu of ACPI idle states");
static struct acpi_processor_power acpi_state_table __initdata;
/**
@@ -1838,6 +1839,11 @@ static bool __init intel_idle_off_by_default(unsigned int flags, u32 mwait_hint)
}
return true;
}
static inline bool ignore_native(void)
{
return no_native && !no_acpi;
}
#else /* !CONFIG_ACPI_PROCESSOR_CSTATE */
#define force_use_acpi (false)
@@ -1847,6 +1853,7 @@ static inline bool intel_idle_off_by_default(unsigned int flags, u32 mwait_hint)
{
return false;
}
static inline bool ignore_native(void) { return false; }
#endif /* !CONFIG_ACPI_PROCESSOR_CSTATE */
/**
@@ -2059,6 +2066,15 @@ static void __init spr_idle_state_table_update(void)
}
}
/**
* byt_cht_auto_demotion_disable - Disable Bay/Cherry Trail auto-demotion.
*/
static void __init byt_cht_auto_demotion_disable(void)
{
wrmsrl(MSR_CC6_DEMOTION_POLICY_CONFIG, 0);
wrmsrl(MSR_MC6_DEMOTION_POLICY_CONFIG, 0);
}
static bool __init intel_idle_verify_cstate(unsigned int mwait_hint)
{
unsigned int mwait_cstate = (MWAIT_HINT2CSTATE(mwait_hint) + 1) &
@@ -2140,6 +2156,10 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv)
case INTEL_ATOM_GRACEMONT:
adl_idle_state_table_update();
break;
case INTEL_ATOM_SILVERMONT:
case INTEL_ATOM_AIRMONT:
byt_cht_auto_demotion_disable();
break;
}
for (cstate = 0; cstate < CPUIDLE_STATE_MAX; ++cstate) {
@@ -2182,11 +2202,6 @@ static void __init intel_idle_init_cstates_icpu(struct cpuidle_driver *drv)
drv->state_count++;
}
if (icpu->byt_auto_demotion_disable_flag) {
wrmsrl(MSR_CC6_DEMOTION_POLICY_CONFIG, 0);
wrmsrl(MSR_MC6_DEMOTION_POLICY_CONFIG, 0);
}
}
/**
@@ -2332,6 +2347,10 @@ static int __init intel_idle_init(void)
pr_debug("MWAIT substates: 0x%x\n", mwait_substates);
icpu = (const struct idle_cpu *)id->driver_data;
if (icpu && ignore_native()) {
pr_debug("ignoring native CPU idle states\n");
icpu = NULL;
}
if (icpu) {
if (icpu->state_table)
cpuidle_state_table = icpu->state_table;