From acccb4cc66676ef3f89c95576903f9a0d970e0d9 Mon Sep 17 00:00:00 2001 From: jinqian Date: Wed, 25 Mar 2015 16:18:44 -0700 Subject: [PATCH] ANDROID: power: wakeup_reason: Report suspend times from last_suspend_time 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 --- .../ABI/testing/sysfs-kernel-wakeup_reasons | 16 +++++++++ kernel/power/wakeup_reason.c | 36 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 Documentation/ABI/testing/sysfs-kernel-wakeup_reasons diff --git a/Documentation/ABI/testing/sysfs-kernel-wakeup_reasons b/Documentation/ABI/testing/sysfs-kernel-wakeup_reasons new file mode 100644 index 000000000000..acb19b91c192 --- /dev/null +++ b/Documentation/ABI/testing/sysfs-kernel-wakeup_reasons @@ -0,0 +1,16 @@ +What: /sys/kernel/wakeup_reasons/last_resume_reason +Date: February 2014 +Contact: Ruchi Kandoi +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 +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 diff --git a/kernel/power/wakeup_reason.c b/kernel/power/wakeup_reason.c index 5944dfe78191..8480e32b41cb 100644 --- a/kernel/power/wakeup_reason.c +++ b/kernel/power/wakeup_reason.c @@ -36,6 +36,11 @@ static char abort_reason[MAX_SUSPEND_ABORT_LEN]; static struct kobject *wakeup_reason; static spinlock_t 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 = { @@ -118,12 +145,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;