PM / Sleep: Add "prevent autosleep time" statistics to wakeup sources
Android uses one wakelock statistics that is only necessary for opportunistic sleep. Namely, the prevent_suspend_time field accumulates the total time the given wakelock has been locked while "automatic suspend" was enabled. Add an analogous field, prevent_sleep_time, to wakeup sources and make it behave in a similar way. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
7483b4a4d9
commit
55850945e8
6 changed files with 102 additions and 5 deletions
|
@ -158,6 +158,17 @@ Description:
|
|||
not enabled to wake up the system from sleep states, this
|
||||
attribute is not present.
|
||||
|
||||
What: /sys/devices/.../power/wakeup_prevent_sleep_time_ms
|
||||
Date: February 2012
|
||||
Contact: Rafael J. Wysocki <rjw@sisk.pl>
|
||||
Description:
|
||||
The /sys/devices/.../wakeup_prevent_sleep_time_ms attribute
|
||||
contains the total time the device has been preventing
|
||||
opportunistic transitions to sleep states from occuring.
|
||||
This attribute is read-only. If the device is not enabled to
|
||||
wake up the system from sleep states, this attribute is not
|
||||
present.
|
||||
|
||||
What: /sys/devices/.../power/autosuspend_delay_ms
|
||||
Date: September 2010
|
||||
Contact: Alan Stern <stern@rowland.harvard.edu>
|
||||
|
|
|
@ -417,6 +417,27 @@ static ssize_t wakeup_last_time_show(struct device *dev,
|
|||
}
|
||||
|
||||
static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL);
|
||||
|
||||
#ifdef CONFIG_PM_AUTOSLEEP
|
||||
static ssize_t wakeup_prevent_sleep_time_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
s64 msec = 0;
|
||||
bool enabled = false;
|
||||
|
||||
spin_lock_irq(&dev->power.lock);
|
||||
if (dev->power.wakeup) {
|
||||
msec = ktime_to_ms(dev->power.wakeup->prevent_sleep_time);
|
||||
enabled = true;
|
||||
}
|
||||
spin_unlock_irq(&dev->power.lock);
|
||||
return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(wakeup_prevent_sleep_time_ms, 0444,
|
||||
wakeup_prevent_sleep_time_show, NULL);
|
||||
#endif /* CONFIG_PM_AUTOSLEEP */
|
||||
#endif /* CONFIG_PM_SLEEP */
|
||||
|
||||
#ifdef CONFIG_PM_ADVANCED_DEBUG
|
||||
|
@ -511,6 +532,9 @@ static struct attribute *wakeup_attrs[] = {
|
|||
&dev_attr_wakeup_total_time_ms.attr,
|
||||
&dev_attr_wakeup_max_time_ms.attr,
|
||||
&dev_attr_wakeup_last_time_ms.attr,
|
||||
#ifdef CONFIG_PM_AUTOSLEEP
|
||||
&dev_attr_wakeup_prevent_sleep_time_ms.attr,
|
||||
#endif
|
||||
#endif
|
||||
NULL,
|
||||
};
|
||||
|
|
|
@ -380,6 +380,8 @@ static void wakeup_source_activate(struct wakeup_source *ws)
|
|||
ws->active = true;
|
||||
ws->active_count++;
|
||||
ws->last_time = ktime_get();
|
||||
if (ws->autosleep_enabled)
|
||||
ws->start_prevent_time = ws->last_time;
|
||||
|
||||
/* Increment the counter of events in progress. */
|
||||
cec = atomic_inc_return(&combined_event_count);
|
||||
|
@ -449,6 +451,17 @@ void pm_stay_awake(struct device *dev)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(pm_stay_awake);
|
||||
|
||||
#ifdef CONFIG_PM_AUTOSLEEP
|
||||
static void update_prevent_sleep_time(struct wakeup_source *ws, ktime_t now)
|
||||
{
|
||||
ktime_t delta = ktime_sub(now, ws->start_prevent_time);
|
||||
ws->prevent_sleep_time = ktime_add(ws->prevent_sleep_time, delta);
|
||||
}
|
||||
#else
|
||||
static inline void update_prevent_sleep_time(struct wakeup_source *ws,
|
||||
ktime_t now) {}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* wakup_source_deactivate - Mark given wakeup source as inactive.
|
||||
* @ws: Wakeup source to handle.
|
||||
|
@ -490,6 +503,9 @@ static void wakeup_source_deactivate(struct wakeup_source *ws)
|
|||
del_timer(&ws->timer);
|
||||
ws->timer_expires = 0;
|
||||
|
||||
if (ws->autosleep_enabled)
|
||||
update_prevent_sleep_time(ws, now);
|
||||
|
||||
/*
|
||||
* Increment the counter of registered wakeup events and decrement the
|
||||
* couter of wakeup events in progress simultaneously.
|
||||
|
@ -718,6 +734,34 @@ bool pm_save_wakeup_count(unsigned int count)
|
|||
return events_check_enabled;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_AUTOSLEEP
|
||||
/**
|
||||
* pm_wakep_autosleep_enabled - Modify autosleep_enabled for all wakeup sources.
|
||||
* @enabled: Whether to set or to clear the autosleep_enabled flags.
|
||||
*/
|
||||
void pm_wakep_autosleep_enabled(bool set)
|
||||
{
|
||||
struct wakeup_source *ws;
|
||||
ktime_t now = ktime_get();
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
|
||||
spin_lock_irq(&ws->lock);
|
||||
if (ws->autosleep_enabled != set) {
|
||||
ws->autosleep_enabled = set;
|
||||
if (ws->active) {
|
||||
if (set)
|
||||
ws->start_prevent_time = now;
|
||||
else
|
||||
update_prevent_sleep_time(ws, now);
|
||||
}
|
||||
}
|
||||
spin_unlock_irq(&ws->lock);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
#endif /* CONFIG_PM_AUTOSLEEP */
|
||||
|
||||
static struct dentry *wakeup_sources_stats_dentry;
|
||||
|
||||
/**
|
||||
|
@ -733,28 +777,37 @@ static int print_wakeup_source_stats(struct seq_file *m,
|
|||
ktime_t max_time;
|
||||
unsigned long active_count;
|
||||
ktime_t active_time;
|
||||
ktime_t prevent_sleep_time;
|
||||
int ret;
|
||||
|
||||
spin_lock_irqsave(&ws->lock, flags);
|
||||
|
||||
total_time = ws->total_time;
|
||||
max_time = ws->max_time;
|
||||
prevent_sleep_time = ws->prevent_sleep_time;
|
||||
active_count = ws->active_count;
|
||||
if (ws->active) {
|
||||
active_time = ktime_sub(ktime_get(), ws->last_time);
|
||||
ktime_t now = ktime_get();
|
||||
|
||||
active_time = ktime_sub(now, ws->last_time);
|
||||
total_time = ktime_add(total_time, active_time);
|
||||
if (active_time.tv64 > max_time.tv64)
|
||||
max_time = active_time;
|
||||
|
||||
if (ws->autosleep_enabled)
|
||||
prevent_sleep_time = ktime_add(prevent_sleep_time,
|
||||
ktime_sub(now, ws->start_prevent_time));
|
||||
} else {
|
||||
active_time = ktime_set(0, 0);
|
||||
}
|
||||
|
||||
ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t"
|
||||
"%lld\t\t%lld\t\t%lld\t\t%lld\n",
|
||||
"%lld\t\t%lld\t\t%lld\t\t%lld\t\t%lld\n",
|
||||
ws->name, active_count, ws->event_count,
|
||||
ws->wakeup_count, ws->expire_count,
|
||||
ktime_to_ms(active_time), ktime_to_ms(total_time),
|
||||
ktime_to_ms(max_time), ktime_to_ms(ws->last_time));
|
||||
ktime_to_ms(max_time), ktime_to_ms(ws->last_time),
|
||||
ktime_to_ms(prevent_sleep_time));
|
||||
|
||||
spin_unlock_irqrestore(&ws->lock, flags);
|
||||
|
||||
|
@ -771,7 +824,7 @@ static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
|
|||
|
||||
seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
|
||||
"expire_count\tactive_since\ttotal_time\tmax_time\t"
|
||||
"last_change\n");
|
||||
"last_change\tprevent_suspend_time\n");
|
||||
|
||||
rcu_read_lock();
|
||||
list_for_each_entry_rcu(ws, &wakeup_sources, entry)
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
* @total_time: Total time this wakeup source has been active.
|
||||
* @max_time: Maximum time this wakeup source has been continuously active.
|
||||
* @last_time: Monotonic clock when the wakeup source's was touched last time.
|
||||
* @prevent_sleep_time: Total time this source has been preventing autosleep.
|
||||
* @event_count: Number of signaled wakeup events.
|
||||
* @active_count: Number of times the wakeup sorce was activated.
|
||||
* @relax_count: Number of times the wakeup sorce was deactivated.
|
||||
|
@ -51,12 +52,15 @@ struct wakeup_source {
|
|||
ktime_t total_time;
|
||||
ktime_t max_time;
|
||||
ktime_t last_time;
|
||||
ktime_t start_prevent_time;
|
||||
ktime_t prevent_sleep_time;
|
||||
unsigned long event_count;
|
||||
unsigned long active_count;
|
||||
unsigned long relax_count;
|
||||
unsigned long expire_count;
|
||||
unsigned long wakeup_count;
|
||||
bool active:1;
|
||||
bool autosleep_enabled:1;
|
||||
};
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
|
|
|
@ -358,6 +358,7 @@ extern bool events_check_enabled;
|
|||
extern bool pm_wakeup_pending(void);
|
||||
extern bool pm_get_wakeup_count(unsigned int *count, bool block);
|
||||
extern bool pm_save_wakeup_count(unsigned int count);
|
||||
extern void pm_wakep_autosleep_enabled(bool set);
|
||||
|
||||
static inline void lock_system_sleep(void)
|
||||
{
|
||||
|
|
|
@ -101,8 +101,12 @@ int pm_autosleep_set_state(suspend_state_t state)
|
|||
|
||||
__pm_relax(autosleep_ws);
|
||||
|
||||
if (state > PM_SUSPEND_ON)
|
||||
if (state > PM_SUSPEND_ON) {
|
||||
pm_wakep_autosleep_enabled(true);
|
||||
queue_up_suspend_work();
|
||||
} else {
|
||||
pm_wakep_autosleep_enabled(false);
|
||||
}
|
||||
|
||||
mutex_unlock(&autosleep_lock);
|
||||
return 0;
|
||||
|
|
Loading…
Reference in a new issue