Power: Report total suspend times from boot in suspend_since_boot

This node exports five values separated by space.
        From left to right:
        1. Amount of suspend/resume cycles
        2. Amount of suspend abort cycles
        3. Total time spent in suspend/resume process
        4. Total time in suspend abort process
        5. Total time spent sleep in suspend state

Change-Id: Ife188fd8386dce35f95fa7ba09fbc9d7e152db62
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
This commit is contained in:
Dmitry Shmidt 2015-04-08 13:28:11 -07:00 committed by Artem Borisov
parent 953a4840dd
commit 563e031bd3

View file

@ -44,8 +44,14 @@ struct completion wakeups_completion;
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 struct timespec last_stime; /* sleep time before last suspend */
static struct timespec curr_stime; /* sleep time after last suspend */
static struct timespec total_xtime; /* total suspend time since boot */
static struct timespec total_stime; /* total sleep time since boot */
static struct timespec total_atime; /* total suspend abort time since boot */
static unsigned long suspend_count; /* total amount of resumes */
static unsigned long abort_count; /* total amount of suspend abort */
static void init_wakeup_irq_node(struct wakeup_irq_node *p, int irq)
{
@ -269,12 +275,28 @@ static ssize_t last_suspend_time_show(struct kobject *kobj,
sleep_time.tv_sec, sleep_time.tv_nsec);
}
static ssize_t suspend_since_boot_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct timespec xtime;
xtime = timespec_sub(total_xtime, total_stime);
return sprintf(buf, "%lu %lu %lu.%09lu %lu.%09lu %lu.%09lu\n",
suspend_count, abort_count,
xtime.tv_sec, xtime.tv_nsec,
total_atime.tv_sec, total_atime.tv_nsec,
total_stime.tv_sec, total_stime.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 kobj_attribute suspend_since_boot = __ATTR_RO(suspend_since_boot);
static struct attribute *attrs[] = {
&resume_reason.attr,
&suspend_time.attr,
&suspend_since_boot.attr,
NULL,
};
static struct attribute_group attr_group = {
@ -496,11 +518,8 @@ static bool delete_node(struct wakeup_irq_node *n, void *unused)
return true;
}
void clear_wakeup_reasons(void)
static void clear_wakeup_reasons_nolock(void)
{
unsigned long flags;
spin_lock_irqsave(&resume_reason_lock, flags);
BUG_ON(logging_wakeup_reasons());
walk_irq_node_tree(base_irq_nodes, delete_node, NULL);
base_irq_nodes = NULL;
@ -508,7 +527,14 @@ void clear_wakeup_reasons(void)
cur_irq_tree_depth = 0;
INIT_LIST_HEAD(&wakeup_irqs);
suspend_abort = false;
}
void clear_wakeup_reasons(void)
{
unsigned long flags;
spin_lock_irqsave(&resume_reason_lock, flags);
clear_wakeup_reasons_nolock();
spin_unlock_irqrestore(&resume_reason_lock, flags);
}
@ -517,10 +543,12 @@ static int wakeup_reason_pm_event(struct notifier_block *notifier,
unsigned long pm_event, void *unused)
{
struct timespec xtom; /* wall_to_monotonic, ignored */
unsigned long flags;
spin_lock_irqsave(&resume_reason_lock, flags);
switch (pm_event) {
case PM_SUSPEND_PREPARE:
clear_wakeup_reasons();
clear_wakeup_reasons_nolock();
get_xtime_and_monotonic_and_sleep_offset(&last_xtime, &xtom,
&last_stime);
@ -529,6 +557,18 @@ static int wakeup_reason_pm_event(struct notifier_block *notifier,
get_xtime_and_monotonic_and_sleep_offset(&curr_xtime, &xtom,
&curr_stime);
if (!suspend_abort) {
suspend_count++;
total_xtime = timespec_add(total_xtime,
timespec_sub(curr_xtime, last_xtime));
total_stime = timespec_add(total_stime,
timespec_sub(curr_stime, last_stime));
} else {
abort_count++;
total_atime = timespec_add(total_atime,
timespec_sub(curr_xtime, last_xtime));
}
/* log_wakeups should have been cleared by now. */
if (WARN_ON(logging_wakeup_reasons())) {
stop_logging_wakeup_reasons();
@ -539,6 +579,7 @@ static int wakeup_reason_pm_event(struct notifier_block *notifier,
default:
break;
}
spin_unlock_irqrestore(&resume_reason_lock, flags);
return NOTIFY_DONE;
}