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
This commit is contained in:
parent
ba32dd1412
commit
acccb4cc66
2 changed files with 52 additions and 0 deletions
16
Documentation/ABI/testing/sysfs-kernel-wakeup_reasons
Normal file
16
Documentation/ABI/testing/sysfs-kernel-wakeup_reasons
Normal file
|
@ -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.
|
|
@ -36,6 +36,11 @@ static char abort_reason[MAX_SUSPEND_ABORT_LEN];
|
||||||
static struct kobject *wakeup_reason;
|
static struct kobject *wakeup_reason;
|
||||||
static spinlock_t resume_reason_lock;
|
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,
|
static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribute *attr,
|
||||||
char *buf)
|
char *buf)
|
||||||
{
|
{
|
||||||
|
@ -59,10 +64,32 @@ static ssize_t last_resume_reason_show(struct kobject *kobj, struct kobj_attribu
|
||||||
return buf_offset;
|
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 resume_reason = __ATTR_RO(last_resume_reason);
|
||||||
|
static struct kobj_attribute suspend_time = __ATTR_RO(last_suspend_time);
|
||||||
|
|
||||||
static struct attribute *attrs[] = {
|
static struct attribute *attrs[] = {
|
||||||
&resume_reason.attr,
|
&resume_reason.attr,
|
||||||
|
&suspend_time.attr,
|
||||||
NULL,
|
NULL,
|
||||||
};
|
};
|
||||||
static struct attribute_group attr_group = {
|
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,
|
static int wakeup_reason_pm_event(struct notifier_block *notifier,
|
||||||
unsigned long pm_event, void *unused)
|
unsigned long pm_event, void *unused)
|
||||||
{
|
{
|
||||||
|
struct timespec xtom; /* wall_to_monotonic, ignored */
|
||||||
|
|
||||||
switch (pm_event) {
|
switch (pm_event) {
|
||||||
case PM_SUSPEND_PREPARE:
|
case PM_SUSPEND_PREPARE:
|
||||||
spin_lock(&resume_reason_lock);
|
spin_lock(&resume_reason_lock);
|
||||||
irqcount = 0;
|
irqcount = 0;
|
||||||
suspend_abort = false;
|
suspend_abort = false;
|
||||||
spin_unlock(&resume_reason_lock);
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in a new issue