Commit 55850945 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki

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: default avatarRafael J. Wysocki <rjw@sisk.pl>
Acked-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 7483b4a4
...@@ -158,6 +158,17 @@ Description: ...@@ -158,6 +158,17 @@ Description:
not enabled to wake up the system from sleep states, this not enabled to wake up the system from sleep states, this
attribute is not present. 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 What: /sys/devices/.../power/autosuspend_delay_ms
Date: September 2010 Date: September 2010
Contact: Alan Stern <stern@rowland.harvard.edu> Contact: Alan Stern <stern@rowland.harvard.edu>
......
...@@ -417,6 +417,27 @@ static ssize_t wakeup_last_time_show(struct device *dev, ...@@ -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); 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 */ #endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM_ADVANCED_DEBUG #ifdef CONFIG_PM_ADVANCED_DEBUG
...@@ -511,6 +532,9 @@ static struct attribute *wakeup_attrs[] = { ...@@ -511,6 +532,9 @@ static struct attribute *wakeup_attrs[] = {
&dev_attr_wakeup_total_time_ms.attr, &dev_attr_wakeup_total_time_ms.attr,
&dev_attr_wakeup_max_time_ms.attr, &dev_attr_wakeup_max_time_ms.attr,
&dev_attr_wakeup_last_time_ms.attr, &dev_attr_wakeup_last_time_ms.attr,
#ifdef CONFIG_PM_AUTOSLEEP
&dev_attr_wakeup_prevent_sleep_time_ms.attr,
#endif
#endif #endif
NULL, NULL,
}; };
......
...@@ -380,6 +380,8 @@ static void wakeup_source_activate(struct wakeup_source *ws) ...@@ -380,6 +380,8 @@ static void wakeup_source_activate(struct wakeup_source *ws)
ws->active = true; ws->active = true;
ws->active_count++; ws->active_count++;
ws->last_time = ktime_get(); ws->last_time = ktime_get();
if (ws->autosleep_enabled)
ws->start_prevent_time = ws->last_time;
/* Increment the counter of events in progress. */ /* Increment the counter of events in progress. */
cec = atomic_inc_return(&combined_event_count); cec = atomic_inc_return(&combined_event_count);
...@@ -449,6 +451,17 @@ void pm_stay_awake(struct device *dev) ...@@ -449,6 +451,17 @@ void pm_stay_awake(struct device *dev)
} }
EXPORT_SYMBOL_GPL(pm_stay_awake); 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. * wakup_source_deactivate - Mark given wakeup source as inactive.
* @ws: Wakeup source to handle. * @ws: Wakeup source to handle.
...@@ -490,6 +503,9 @@ static void wakeup_source_deactivate(struct wakeup_source *ws) ...@@ -490,6 +503,9 @@ static void wakeup_source_deactivate(struct wakeup_source *ws)
del_timer(&ws->timer); del_timer(&ws->timer);
ws->timer_expires = 0; ws->timer_expires = 0;
if (ws->autosleep_enabled)
update_prevent_sleep_time(ws, now);
/* /*
* Increment the counter of registered wakeup events and decrement the * Increment the counter of registered wakeup events and decrement the
* couter of wakeup events in progress simultaneously. * couter of wakeup events in progress simultaneously.
...@@ -718,6 +734,34 @@ bool pm_save_wakeup_count(unsigned int count) ...@@ -718,6 +734,34 @@ bool pm_save_wakeup_count(unsigned int count)
return events_check_enabled; 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; static struct dentry *wakeup_sources_stats_dentry;
/** /**
...@@ -733,28 +777,37 @@ static int print_wakeup_source_stats(struct seq_file *m, ...@@ -733,28 +777,37 @@ static int print_wakeup_source_stats(struct seq_file *m,
ktime_t max_time; ktime_t max_time;
unsigned long active_count; unsigned long active_count;
ktime_t active_time; ktime_t active_time;
ktime_t prevent_sleep_time;
int ret; int ret;
spin_lock_irqsave(&ws->lock, flags); spin_lock_irqsave(&ws->lock, flags);
total_time = ws->total_time; total_time = ws->total_time;
max_time = ws->max_time; max_time = ws->max_time;
prevent_sleep_time = ws->prevent_sleep_time;
active_count = ws->active_count; active_count = ws->active_count;
if (ws->active) { 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); total_time = ktime_add(total_time, active_time);
if (active_time.tv64 > max_time.tv64) if (active_time.tv64 > max_time.tv64)
max_time = active_time; max_time = active_time;
if (ws->autosleep_enabled)
prevent_sleep_time = ktime_add(prevent_sleep_time,
ktime_sub(now, ws->start_prevent_time));
} else { } else {
active_time = ktime_set(0, 0); active_time = ktime_set(0, 0);
} }
ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t" 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->name, active_count, ws->event_count,
ws->wakeup_count, ws->expire_count, ws->wakeup_count, ws->expire_count,
ktime_to_ms(active_time), ktime_to_ms(total_time), 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); spin_unlock_irqrestore(&ws->lock, flags);
...@@ -771,7 +824,7 @@ static int wakeup_sources_stats_show(struct seq_file *m, void *unused) ...@@ -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" seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
"expire_count\tactive_since\ttotal_time\tmax_time\t" "expire_count\tactive_since\ttotal_time\tmax_time\t"
"last_change\n"); "last_change\tprevent_suspend_time\n");
rcu_read_lock(); rcu_read_lock();
list_for_each_entry_rcu(ws, &wakeup_sources, entry) list_for_each_entry_rcu(ws, &wakeup_sources, entry)
......
...@@ -34,6 +34,7 @@ ...@@ -34,6 +34,7 @@
* @total_time: Total time this wakeup source has been active. * @total_time: Total time this wakeup source has been active.
* @max_time: Maximum time this wakeup source has been continuously 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. * @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. * @event_count: Number of signaled wakeup events.
* @active_count: Number of times the wakeup sorce was activated. * @active_count: Number of times the wakeup sorce was activated.
* @relax_count: Number of times the wakeup sorce was deactivated. * @relax_count: Number of times the wakeup sorce was deactivated.
...@@ -51,12 +52,15 @@ struct wakeup_source { ...@@ -51,12 +52,15 @@ struct wakeup_source {
ktime_t total_time; ktime_t total_time;
ktime_t max_time; ktime_t max_time;
ktime_t last_time; ktime_t last_time;
ktime_t start_prevent_time;
ktime_t prevent_sleep_time;
unsigned long event_count; unsigned long event_count;
unsigned long active_count; unsigned long active_count;
unsigned long relax_count; unsigned long relax_count;
unsigned long expire_count; unsigned long expire_count;
unsigned long wakeup_count; unsigned long wakeup_count;
bool active:1; bool active:1;
bool autosleep_enabled:1;
}; };
#ifdef CONFIG_PM_SLEEP #ifdef CONFIG_PM_SLEEP
......
...@@ -358,6 +358,7 @@ extern bool events_check_enabled; ...@@ -358,6 +358,7 @@ extern bool events_check_enabled;
extern bool pm_wakeup_pending(void); extern bool pm_wakeup_pending(void);
extern bool pm_get_wakeup_count(unsigned int *count, bool block); extern bool pm_get_wakeup_count(unsigned int *count, bool block);
extern bool pm_save_wakeup_count(unsigned int count); extern bool pm_save_wakeup_count(unsigned int count);
extern void pm_wakep_autosleep_enabled(bool set);
static inline void lock_system_sleep(void) static inline void lock_system_sleep(void)
{ {
......
...@@ -101,8 +101,12 @@ int pm_autosleep_set_state(suspend_state_t state) ...@@ -101,8 +101,12 @@ int pm_autosleep_set_state(suspend_state_t state)
__pm_relax(autosleep_ws); __pm_relax(autosleep_ws);
if (state > PM_SUSPEND_ON) if (state > PM_SUSPEND_ON) {
pm_wakep_autosleep_enabled(true);
queue_up_suspend_work(); queue_up_suspend_work();
} else {
pm_wakep_autosleep_enabled(false);
}
mutex_unlock(&autosleep_lock); mutex_unlock(&autosleep_lock);
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment