cpuidle: record state entry rejection statistics
authorLina Iyer <ilina@codeaurora.org>
Tue, 22 Sep 2020 18:34:16 +0000 (12:34 -0600)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Wed, 23 Sep 2020 12:10:31 +0000 (14:10 +0200)
CPUs may fail to enter the chosen idle state if there was a
pending interrupt, causing the cpuidle driver to return an error
value.

Record that and export it via sysfs along with the other idle state
statistics.

This could prove useful in understanding behavior of the governor
and the system during usecases that involve multiple CPUs.

Signed-off-by: Lina Iyer <ilina@codeaurora.org>
[ rjw: Changelog and documentation edits ]
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Documentation/admin-guide/pm/cpuidle.rst
drivers/cpuidle/cpuidle.c
drivers/cpuidle/sysfs.c
include/linux/cpuidle.h

index a96a423e37791862339b2303b555f5b5a2a6ac99..830868e526f482963c1444a78e93b8d857932cf6 100644 (file)
@@ -528,6 +528,10 @@ object corresponding to it, as follows:
        Total number of times the hardware has been asked by the given CPU to
        enter this idle state.
 
+``rejected``
+       Total number of times a request to enter this idle state on the given
+       CPU was rejected.
+
 The :file:`desc` and :file:`name` files both contain strings.  The difference
 between them is that the name is expected to be more concise, while the
 description may be longer and it may contain white space or special characters.
@@ -572,6 +576,11 @@ particular case.  For these reasons, the only reliable way to find out how
 much time has been spent by the hardware in different idle states supported by
 it is to use idle state residency counters in the hardware, if available.
 
+Generally, an interrupt received when trying to enter an idle state causes the
+idle state entry request to be rejected, in which case the ``CPUIdle`` driver
+may return an error code to indicate that this was the case. The :file:`usage`
+and :file:`rejected` files report the number of times the given idle state
+was entered successfully or rejected, respectively.
 
 .. _cpu-pm-qos:
 
index 6c7e5621cf9a8d6640d7e922eb275bd1dafb6fbe..0ed5030b89d6d796ca5af9986a269ad139317f1a 100644 (file)
@@ -307,6 +307,7 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv,
                }
        } else {
                dev->last_residency_ns = 0;
+               dev->states_usage[index].rejected++;
        }
 
        return entered_state;
index 091d1caceb4174cd411cc78b42752fe0c4942fb0..53ec9585ccd448eda6f8955553642d337745cef7 100644 (file)
@@ -256,6 +256,7 @@ define_show_state_time_function(exit_latency)
 define_show_state_time_function(target_residency)
 define_show_state_function(power_usage)
 define_show_state_ull_function(usage)
+define_show_state_ull_function(rejected)
 define_show_state_str_function(name)
 define_show_state_str_function(desc)
 define_show_state_ull_function(above)
@@ -312,6 +313,7 @@ define_one_state_ro(latency, show_state_exit_latency);
 define_one_state_ro(residency, show_state_target_residency);
 define_one_state_ro(power, show_state_power_usage);
 define_one_state_ro(usage, show_state_usage);
+define_one_state_ro(rejected, show_state_rejected);
 define_one_state_ro(time, show_state_time);
 define_one_state_rw(disable, show_state_disable, store_state_disable);
 define_one_state_ro(above, show_state_above);
@@ -325,6 +327,7 @@ static struct attribute *cpuidle_state_default_attrs[] = {
        &attr_residency.attr,
        &attr_power.attr,
        &attr_usage.attr,
+       &attr_rejected.attr,
        &attr_time.attr,
        &attr_disable.attr,
        &attr_above.attr,
index 6175c77bf25e7ae941ccb033121f3bc0c5c407bf..ed0da0e58e8b00c3607ea231f5b86eb1dc7b957c 100644 (file)
@@ -38,6 +38,7 @@ struct cpuidle_state_usage {
        u64                     time_ns;
        unsigned long long      above; /* Number of times it's been too deep */
        unsigned long long      below; /* Number of times it's been too shallow */
+       unsigned long long      rejected; /* Number of times idle entry was rejected */
 #ifdef CONFIG_SUSPEND
        unsigned long long      s2idle_usage;
        unsigned long long      s2idle_time; /* in US */