Power: Report suspend times from last_suspend_time
jinqian [Wed, 25 Mar 2015 23:18:44 +0000 (16:18 -0700)]
This node epxorts two values separated by space.
From left to right:
1. time spent in suspend/resume process
2. time spent sleep in suspend state

Change-Id: I2cb9a9408a5fd12166aaec11b935a0fd6a408c63

Documentation/ABI/testing/sysfs-kernel-wakeup_reasons [new file with mode: 0644]
kernel/power/wakeup_reason.c

diff --git a/Documentation/ABI/testing/sysfs-kernel-wakeup_reasons b/Documentation/ABI/testing/sysfs-kernel-wakeup_reasons
new file mode 100644 (file)
index 0000000..acb19b9
--- /dev/null
@@ -0,0 +1,16 @@
+What:          /sys/kernel/wakeup_reasons/last_resume_reason
+Date:          February 2014
+Contact:       Ruchi Kandoi <kandoiruchi@google.com>
+Description:
+               The /sys/kernel/wakeup_reasons/last_resume_reason is
+               used to report wakeup reasons after system exited suspend.
+
+What:          /sys/kernel/wakeup_reasons/last_suspend_time
+Date:          March 2015
+Contact:       jinqian <jinqian@google.com>
+Description:
+               The /sys/kernel/wakeup_reasons/last_suspend_time is
+               used to report time spent in last suspend cycle. It contains
+               two numbers (in seconds) separated by space. First number is
+               the time spent in suspend and resume processes. Second number
+               is the time spent in sleep state.
\ No newline at end of file
index 085c99e..76b5340 100644 (file)
@@ -36,6 +36,11 @@ static char abort_reason[MAX_SUSPEND_ABORT_LEN];
 static struct kobject *wakeup_reason;
 static DEFINE_SPINLOCK(resume_reason_lock);
 
+static struct timespec last_xtime; /* wall time before last suspend */
+static struct timespec curr_xtime; /* wall time after last suspend */
+static struct timespec last_stime; /* total_sleep_time before last suspend */
+static struct timespec curr_stime; /* total_sleep_time after last suspend */
+
 static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribute *attr,
                char *buf)
 {
@@ -59,10 +64,32 @@ static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribu
        return buf_offset;
 }
 
+static ssize_t last_suspend_time_show(struct kobject *kobj,
+                       struct kobj_attribute *attr, char *buf)
+{
+       struct timespec sleep_time;
+       struct timespec total_time;
+       struct timespec suspend_resume_time;
+
+       sleep_time = timespec_sub(curr_stime, last_stime);
+       total_time = timespec_sub(curr_xtime, last_xtime);
+       suspend_resume_time = timespec_sub(total_time, sleep_time);
+
+       /*
+        * suspend_resume_time is calculated from sleep_time. Userspace would
+        * always need both. Export them in pair here.
+        */
+       return sprintf(buf, "%lu.%09lu %lu.%09lu\n",
+                               suspend_resume_time.tv_sec, suspend_resume_time.tv_nsec,
+                               sleep_time.tv_sec, sleep_time.tv_nsec);
+}
+
 static struct kobj_attribute resume_reason = __ATTR_RO(last_resume_reason);
+static struct kobj_attribute suspend_time = __ATTR_RO(last_suspend_time);
 
 static struct attribute *attrs[] = {
        &resume_reason.attr,
+       &suspend_time.attr,
        NULL,
 };
 static struct attribute_group attr_group = {
@@ -133,12 +160,21 @@ void log_suspend_abort_reason(const char *fmt, ...)
 static int wakeup_reason_pm_event(struct notifier_block *notifier,
                unsigned long pm_event, void *unused)
 {
+       struct timespec xtom; /* wall_to_monotonic, ignored */
+
        switch (pm_event) {
        case PM_SUSPEND_PREPARE:
                spin_lock(&resume_reason_lock);
                irqcount = 0;
                suspend_abort = false;
                spin_unlock(&resume_reason_lock);
+
+               get_xtime_and_monotonic_and_sleep_offset(&last_xtime, &xtom,
+                       &last_stime);
+               break;
+       case PM_POST_SUSPEND:
+               get_xtime_and_monotonic_and_sleep_offset(&curr_xtime, &xtom,
+                       &curr_stime);
                break;
        default:
                break;