PM / Domains: Add time accounting to various genpd states
authorThara Gopinath <thara.gopinath@linaro.org>
Fri, 14 Jul 2017 17:10:15 +0000 (13:10 -0400)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Mon, 24 Jul 2017 21:02:02 +0000 (23:02 +0200)
This patch adds support to calculate the time spent by the generic
power domains in on and various idle states.

Signed-off-by: Thara Gopinath <thara.gopinath@linaro.org>
Acked-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
drivers/base/power/domain.c
include/linux/pm_domain.h

index 60303aa28587b9079317a8fc3500ef1aa70ec247..431488914982e8747a1a94cc87fb4fd06fa9ada9 100644 (file)
@@ -209,6 +209,34 @@ static void genpd_sd_counter_inc(struct generic_pm_domain *genpd)
        smp_mb__after_atomic();
 }
 
+#ifdef CONFIG_DEBUG_FS
+static void genpd_update_accounting(struct generic_pm_domain *genpd)
+{
+       ktime_t delta, now;
+
+       now = ktime_get();
+       delta = ktime_sub(now, genpd->accounting_time);
+
+       /*
+        * If genpd->status is active, it means we are just
+        * out of off and so update the idle time and vice
+        * versa.
+        */
+       if (genpd->status == GPD_STATE_ACTIVE) {
+               int state_idx = genpd->state_idx;
+
+               genpd->states[state_idx].idle_time =
+                       ktime_add(genpd->states[state_idx].idle_time, delta);
+       } else {
+               genpd->on_time = ktime_add(genpd->on_time, delta);
+       }
+
+       genpd->accounting_time = now;
+}
+#else
+static inline void genpd_update_accounting(struct generic_pm_domain *genpd) {}
+#endif
+
 static int _genpd_power_on(struct generic_pm_domain *genpd, bool timed)
 {
        unsigned int state_idx = genpd->state_idx;
@@ -361,6 +389,7 @@ static int genpd_power_off(struct generic_pm_domain *genpd, bool one_dev_on,
        }
 
        genpd->status = GPD_STATE_POWER_OFF;
+       genpd_update_accounting(genpd);
 
        list_for_each_entry(link, &genpd->slave_links, slave_node) {
                genpd_sd_counter_dec(link->master);
@@ -413,6 +442,8 @@ static int genpd_power_on(struct generic_pm_domain *genpd, unsigned int depth)
                goto err;
 
        genpd->status = GPD_STATE_ACTIVE;
+       genpd_update_accounting(genpd);
+
        return 0;
 
  err:
@@ -1540,6 +1571,7 @@ int pm_genpd_init(struct generic_pm_domain *genpd,
        genpd->max_off_time_changed = true;
        genpd->provider = NULL;
        genpd->has_provider = false;
+       genpd->accounting_time = ktime_get();
        genpd->domain.ops.runtime_suspend = genpd_runtime_suspend;
        genpd->domain.ops.runtime_resume = genpd_runtime_resume;
        genpd->domain.ops.prepare = pm_genpd_prepare;
index 41004d97cefae2d9c0565b343a85743788c5e9d3..84f423d5633ee996e7eb5dd87ed8d3024f41b886 100644 (file)
@@ -43,6 +43,7 @@ struct genpd_power_state {
        s64 power_on_latency_ns;
        s64 residency_ns;
        struct fwnode_handle *fwnode;
+       ktime_t idle_time;
 };
 
 struct genpd_lock_ops;
@@ -78,6 +79,8 @@ struct generic_pm_domain {
        unsigned int state_count; /* number of states */
        unsigned int state_idx; /* state that genpd will go to when off */
        void *free; /* Free the state that was allocated for default */
+       ktime_t on_time;
+       ktime_t accounting_time;
        const struct genpd_lock_ops *lock_ops;
        union {
                struct mutex mlock;