]> www.infradead.org Git - users/jedix/linux-maple.git/commitdiff
pmdomain: core: Add residency reflection for domain-idlestates to debugfs
authorUlf Hansson <ulf.hansson@linaro.org>
Fri, 14 Mar 2025 10:00:58 +0000 (11:00 +0100)
committerUlf Hansson <ulf.hansson@linaro.org>
Wed, 23 Apr 2025 08:08:34 +0000 (10:08 +0200)
For regular cpuidle states we are reflecting over the selected/entered
state to see if the sleep-duration meets the residency for the state. The
output from the reflection is an "above" value to indicate the number of
times the state was too deep and a "below" value for the number of times it
was too shallow.

Let's implement the similar thing for genpd's domain-idlestates along with
genpd's governor and put the information in the genpd's debugfs.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Link: https://lore.kernel.org/r/20250314100103.1294715-5-ulf.hansson@linaro.org
drivers/pmdomain/core.c
drivers/pmdomain/governor.c
include/linux/pm_domain.h

index c79ef6e3ab85b1ca2f9940a7f7f744a3557074c8..3327de2f9ed231479689de4ef72316d1a6426b37 100644 (file)
@@ -304,10 +304,40 @@ static void genpd_update_accounting(struct generic_pm_domain *genpd)
 
        genpd->accounting_time = now;
 }
+
+static void genpd_reflect_residency(struct generic_pm_domain *genpd)
+{
+       struct genpd_governor_data *gd = genpd->gd;
+       struct genpd_power_state *state, *next_state;
+       unsigned int state_idx;
+       s64 sleep_ns, target_ns;
+
+       if (!gd || !gd->reflect_residency)
+               return;
+
+       sleep_ns = ktime_to_ns(ktime_sub(ktime_get(), gd->last_enter));
+       state_idx = genpd->state_idx;
+       state = &genpd->states[state_idx];
+       target_ns = state->power_off_latency_ns + state->residency_ns;
+
+       if (sleep_ns < target_ns) {
+               state->above++;
+       } else if (state_idx < (genpd->state_count -1)) {
+               next_state = &genpd->states[state_idx + 1];
+               target_ns = next_state->power_off_latency_ns +
+                       next_state->residency_ns;
+
+               if (sleep_ns >= target_ns)
+                       state->below++;
+       }
+
+       gd->reflect_residency = false;
+}
 #else
 static inline void genpd_debug_add(struct generic_pm_domain *genpd) {}
 static inline void genpd_debug_remove(struct generic_pm_domain *genpd) {}
 static inline void genpd_update_accounting(struct generic_pm_domain *genpd) {}
+static inline void genpd_reflect_residency(struct generic_pm_domain *genpd) {}
 #endif
 
 static int _genpd_reeval_performance_state(struct generic_pm_domain *genpd,
@@ -982,6 +1012,9 @@ static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth)
        if (genpd_status_on(genpd))
                return 0;
 
+       /* Reflect over the entered idle-states residency for debugfs. */
+       genpd_reflect_residency(genpd);
+
        /*
         * The list is guaranteed not to change while the loop below is being
         * executed, unless one of the parents' .power_on() callbacks fiddles
@@ -3517,7 +3550,7 @@ static int idle_states_show(struct seq_file *s, void *data)
        if (ret)
                return -ERESTARTSYS;
 
-       seq_puts(s, "State          Time Spent(ms) Usage          Rejected\n");
+       seq_puts(s, "State          Time Spent(ms) Usage      Rejected   Above      Below\n");
 
        for (i = 0; i < genpd->state_count; i++) {
                struct genpd_power_state *state = &genpd->states[i];
@@ -3537,9 +3570,10 @@ static int idle_states_show(struct seq_file *s, void *data)
                        snprintf(state_name, ARRAY_SIZE(state_name), "S%-13d", i);
 
                do_div(idle_time, NSEC_PER_MSEC);
-               seq_printf(s, "%-14s %-14llu %-14llu %llu\n",
+               seq_printf(s, "%-14s %-14llu %-10llu %-10llu %-10llu %llu\n",
                           state->name ?: state_name, idle_time,
-                          state->usage, state->rejected);
+                          state->usage, state->rejected, state->above,
+                          state->below);
        }
 
        genpd_unlock(genpd);
index d1a10eeebd1616a4c9a33155b8a04ac8f44b45ae..c1e148657c873a6b5b4d9c0f058d54cb020c56e2 100644 (file)
@@ -392,6 +392,8 @@ static bool cpu_power_down_ok(struct dev_pm_domain *pd)
                if (idle_duration_ns >= (genpd->states[i].residency_ns +
                    genpd->states[i].power_off_latency_ns)) {
                        genpd->state_idx = i;
+                       genpd->gd->last_enter = now;
+                       genpd->gd->reflect_residency = true;
                        return true;
                }
        } while (--i >= 0);
index 6e808aeecbcbdea837682276a0fbf9b4cac71619..0b18160901a2c9ea4281118f00d17ae803327316 100644 (file)
@@ -142,6 +142,8 @@ struct genpd_governor_data {
        bool max_off_time_changed;
        ktime_t next_wakeup;
        ktime_t next_hrtimer;
+       ktime_t last_enter;
+       bool reflect_residency;
        bool cached_power_down_ok;
        bool cached_power_down_state_idx;
 };
@@ -153,6 +155,8 @@ struct genpd_power_state {
        s64 residency_ns;
        u64 usage;
        u64 rejected;
+       u64 above;
+       u64 below;
        struct fwnode_handle *fwnode;
        u64 idle_time;
        void *data;