aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2012-04-29 16:53:32 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-05-01 15:25:49 -0400
commit55850945e872531644f31fefd217d61dd15dcab8 (patch)
tree412ee1338d0b69e4d6e2a5e518e30e6660704921
parent7483b4a4d9abf9dcf1ffe6e805ead2847ec3264e (diff)
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>
-rw-r--r--Documentation/ABI/testing/sysfs-devices-power11
-rw-r--r--drivers/base/power/sysfs.c24
-rw-r--r--drivers/base/power/wakeup.c61
-rw-r--r--include/linux/pm_wakeup.h4
-rw-r--r--include/linux/suspend.h1
-rw-r--r--kernel/power/autosleep.c6
6 files changed, 102 insertions, 5 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power
index b0a5d9a6135e..45000f0db4d4 100644
--- a/Documentation/ABI/testing/sysfs-devices-power
+++ b/Documentation/ABI/testing/sysfs-devices-power
@@ -158,6 +158,17 @@ Description:
158 not enabled to wake up the system from sleep states, this 158 not enabled to wake up the system from sleep states, this
159 attribute is not present. 159 attribute is not present.
160 160
161What: /sys/devices/.../power/wakeup_prevent_sleep_time_ms
162Date: February 2012
163Contact: Rafael J. Wysocki <rjw@sisk.pl>
164Description:
165 The /sys/devices/.../wakeup_prevent_sleep_time_ms attribute
166 contains the total time the device has been preventing
167 opportunistic transitions to sleep states from occuring.
168 This attribute is read-only. If the device is not enabled to
169 wake up the system from sleep states, this attribute is not
170 present.
171
161What: /sys/devices/.../power/autosuspend_delay_ms 172What: /sys/devices/.../power/autosuspend_delay_ms
162Date: September 2010 173Date: September 2010
163Contact: Alan Stern <stern@rowland.harvard.edu> 174Contact: Alan Stern <stern@rowland.harvard.edu>
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 13e40b9021b9..48be2ad4dd2c 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -417,6 +417,27 @@ static ssize_t wakeup_last_time_show(struct device *dev,
417} 417}
418 418
419static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL); 419static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL);
420
421#ifdef CONFIG_PM_AUTOSLEEP
422static ssize_t wakeup_prevent_sleep_time_show(struct device *dev,
423 struct device_attribute *attr,
424 char *buf)
425{
426 s64 msec = 0;
427 bool enabled = false;
428
429 spin_lock_irq(&dev->power.lock);
430 if (dev->power.wakeup) {
431 msec = ktime_to_ms(dev->power.wakeup->prevent_sleep_time);
432 enabled = true;
433 }
434 spin_unlock_irq(&dev->power.lock);
435 return enabled ? sprintf(buf, "%lld\n", msec) : sprintf(buf, "\n");
436}
437
438static DEVICE_ATTR(wakeup_prevent_sleep_time_ms, 0444,
439 wakeup_prevent_sleep_time_show, NULL);
440#endif /* CONFIG_PM_AUTOSLEEP */
420#endif /* CONFIG_PM_SLEEP */ 441#endif /* CONFIG_PM_SLEEP */
421 442
422#ifdef CONFIG_PM_ADVANCED_DEBUG 443#ifdef CONFIG_PM_ADVANCED_DEBUG
@@ -511,6 +532,9 @@ static struct attribute *wakeup_attrs[] = {
511 &dev_attr_wakeup_total_time_ms.attr, 532 &dev_attr_wakeup_total_time_ms.attr,
512 &dev_attr_wakeup_max_time_ms.attr, 533 &dev_attr_wakeup_max_time_ms.attr,
513 &dev_attr_wakeup_last_time_ms.attr, 534 &dev_attr_wakeup_last_time_ms.attr,
535#ifdef CONFIG_PM_AUTOSLEEP
536 &dev_attr_wakeup_prevent_sleep_time_ms.attr,
537#endif
514#endif 538#endif
515 NULL, 539 NULL,
516}; 540};
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index cf1706df7610..2595b8d8fe1f 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -380,6 +380,8 @@ static void wakeup_source_activate(struct wakeup_source *ws)
380 ws->active = true; 380 ws->active = true;
381 ws->active_count++; 381 ws->active_count++;
382 ws->last_time = ktime_get(); 382 ws->last_time = ktime_get();
383 if (ws->autosleep_enabled)
384 ws->start_prevent_time = ws->last_time;
383 385
384 /* Increment the counter of events in progress. */ 386 /* Increment the counter of events in progress. */
385 cec = atomic_inc_return(&combined_event_count); 387 cec = atomic_inc_return(&combined_event_count);
@@ -449,6 +451,17 @@ void pm_stay_awake(struct device *dev)
449} 451}
450EXPORT_SYMBOL_GPL(pm_stay_awake); 452EXPORT_SYMBOL_GPL(pm_stay_awake);
451 453
454#ifdef CONFIG_PM_AUTOSLEEP
455static void update_prevent_sleep_time(struct wakeup_source *ws, ktime_t now)
456{
457 ktime_t delta = ktime_sub(now, ws->start_prevent_time);
458 ws->prevent_sleep_time = ktime_add(ws->prevent_sleep_time, delta);
459}
460#else
461static inline void update_prevent_sleep_time(struct wakeup_source *ws,
462 ktime_t now) {}
463#endif
464
452/** 465/**
453 * wakup_source_deactivate - Mark given wakeup source as inactive. 466 * wakup_source_deactivate - Mark given wakeup source as inactive.
454 * @ws: Wakeup source to handle. 467 * @ws: Wakeup source to handle.
@@ -490,6 +503,9 @@ static void wakeup_source_deactivate(struct wakeup_source *ws)
490 del_timer(&ws->timer); 503 del_timer(&ws->timer);
491 ws->timer_expires = 0; 504 ws->timer_expires = 0;
492 505
506 if (ws->autosleep_enabled)
507 update_prevent_sleep_time(ws, now);
508
493 /* 509 /*
494 * Increment the counter of registered wakeup events and decrement the 510 * Increment the counter of registered wakeup events and decrement the
495 * couter of wakeup events in progress simultaneously. 511 * couter of wakeup events in progress simultaneously.
@@ -718,6 +734,34 @@ bool pm_save_wakeup_count(unsigned int count)
718 return events_check_enabled; 734 return events_check_enabled;
719} 735}
720 736
737#ifdef CONFIG_PM_AUTOSLEEP
738/**
739 * pm_wakep_autosleep_enabled - Modify autosleep_enabled for all wakeup sources.
740 * @enabled: Whether to set or to clear the autosleep_enabled flags.
741 */
742void pm_wakep_autosleep_enabled(bool set)
743{
744 struct wakeup_source *ws;
745 ktime_t now = ktime_get();
746
747 rcu_read_lock();
748 list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
749 spin_lock_irq(&ws->lock);
750 if (ws->autosleep_enabled != set) {
751 ws->autosleep_enabled = set;
752 if (ws->active) {
753 if (set)
754 ws->start_prevent_time = now;
755 else
756 update_prevent_sleep_time(ws, now);
757 }
758 }
759 spin_unlock_irq(&ws->lock);
760 }
761 rcu_read_unlock();
762}
763#endif /* CONFIG_PM_AUTOSLEEP */
764
721static struct dentry *wakeup_sources_stats_dentry; 765static struct dentry *wakeup_sources_stats_dentry;
722 766
723/** 767/**
@@ -733,28 +777,37 @@ static int print_wakeup_source_stats(struct seq_file *m,
733 ktime_t max_time; 777 ktime_t max_time;
734 unsigned long active_count; 778 unsigned long active_count;
735 ktime_t active_time; 779 ktime_t active_time;
780 ktime_t prevent_sleep_time;
736 int ret; 781 int ret;
737 782
738 spin_lock_irqsave(&ws->lock, flags); 783 spin_lock_irqsave(&ws->lock, flags);
739 784
740 total_time = ws->total_time; 785 total_time = ws->total_time;
741 max_time = ws->max_time; 786 max_time = ws->max_time;
787 prevent_sleep_time = ws->prevent_sleep_time;
742 active_count = ws->active_count; 788 active_count = ws->active_count;
743 if (ws->active) { 789 if (ws->active) {
744 active_time = ktime_sub(ktime_get(), ws->last_time); 790 ktime_t now = ktime_get();
791
792 active_time = ktime_sub(now, ws->last_time);
745 total_time = ktime_add(total_time, active_time); 793 total_time = ktime_add(total_time, active_time);
746 if (active_time.tv64 > max_time.tv64) 794 if (active_time.tv64 > max_time.tv64)
747 max_time = active_time; 795 max_time = active_time;
796
797 if (ws->autosleep_enabled)
798 prevent_sleep_time = ktime_add(prevent_sleep_time,
799 ktime_sub(now, ws->start_prevent_time));
748 } else { 800 } else {
749 active_time = ktime_set(0, 0); 801 active_time = ktime_set(0, 0);
750 } 802 }
751 803
752 ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t" 804 ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t%lu\t\t"
753 "%lld\t\t%lld\t\t%lld\t\t%lld\n", 805 "%lld\t\t%lld\t\t%lld\t\t%lld\t\t%lld\n",
754 ws->name, active_count, ws->event_count, 806 ws->name, active_count, ws->event_count,
755 ws->wakeup_count, ws->expire_count, 807 ws->wakeup_count, ws->expire_count,
756 ktime_to_ms(active_time), ktime_to_ms(total_time), 808 ktime_to_ms(active_time), ktime_to_ms(total_time),
757 ktime_to_ms(max_time), ktime_to_ms(ws->last_time)); 809 ktime_to_ms(max_time), ktime_to_ms(ws->last_time),
810 ktime_to_ms(prevent_sleep_time));
758 811
759 spin_unlock_irqrestore(&ws->lock, flags); 812 spin_unlock_irqrestore(&ws->lock, flags);
760 813
@@ -771,7 +824,7 @@ static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
771 824
772 seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t" 825 seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
773 "expire_count\tactive_since\ttotal_time\tmax_time\t" 826 "expire_count\tactive_since\ttotal_time\tmax_time\t"
774 "last_change\n"); 827 "last_change\tprevent_suspend_time\n");
775 828
776 rcu_read_lock(); 829 rcu_read_lock();
777 list_for_each_entry_rcu(ws, &wakeup_sources, entry) 830 list_for_each_entry_rcu(ws, &wakeup_sources, entry)
diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h
index 5285317a612a..569781faa504 100644
--- a/include/linux/pm_wakeup.h
+++ b/include/linux/pm_wakeup.h
@@ -34,6 +34,7 @@
34 * @total_time: Total time this wakeup source has been active. 34 * @total_time: Total time this wakeup source has been active.
35 * @max_time: Maximum time this wakeup source has been continuously active. 35 * @max_time: Maximum time this wakeup source has been continuously active.
36 * @last_time: Monotonic clock when the wakeup source's was touched last time. 36 * @last_time: Monotonic clock when the wakeup source's was touched last time.
37 * @prevent_sleep_time: Total time this source has been preventing autosleep.
37 * @event_count: Number of signaled wakeup events. 38 * @event_count: Number of signaled wakeup events.
38 * @active_count: Number of times the wakeup sorce was activated. 39 * @active_count: Number of times the wakeup sorce was activated.
39 * @relax_count: Number of times the wakeup sorce was deactivated. 40 * @relax_count: Number of times the wakeup sorce was deactivated.
@@ -51,12 +52,15 @@ struct wakeup_source {
51 ktime_t total_time; 52 ktime_t total_time;
52 ktime_t max_time; 53 ktime_t max_time;
53 ktime_t last_time; 54 ktime_t last_time;
55 ktime_t start_prevent_time;
56 ktime_t prevent_sleep_time;
54 unsigned long event_count; 57 unsigned long event_count;
55 unsigned long active_count; 58 unsigned long active_count;
56 unsigned long relax_count; 59 unsigned long relax_count;
57 unsigned long expire_count; 60 unsigned long expire_count;
58 unsigned long wakeup_count; 61 unsigned long wakeup_count;
59 bool active:1; 62 bool active:1;
63 bool autosleep_enabled:1;
60}; 64};
61 65
62#ifdef CONFIG_PM_SLEEP 66#ifdef CONFIG_PM_SLEEP
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index 76b7ec7d3a81..cd83059fb592 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -358,6 +358,7 @@ extern bool events_check_enabled;
358extern bool pm_wakeup_pending(void); 358extern bool pm_wakeup_pending(void);
359extern bool pm_get_wakeup_count(unsigned int *count, bool block); 359extern bool pm_get_wakeup_count(unsigned int *count, bool block);
360extern bool pm_save_wakeup_count(unsigned int count); 360extern bool pm_save_wakeup_count(unsigned int count);
361extern void pm_wakep_autosleep_enabled(bool set);
361 362
362static inline void lock_system_sleep(void) 363static inline void lock_system_sleep(void)
363{ 364{
diff --git a/kernel/power/autosleep.c b/kernel/power/autosleep.c
index 42348e3589d3..ca304046d9e2 100644
--- a/kernel/power/autosleep.c
+++ b/kernel/power/autosleep.c
@@ -101,8 +101,12 @@ int pm_autosleep_set_state(suspend_state_t state)
101 101
102 __pm_relax(autosleep_ws); 102 __pm_relax(autosleep_ws);
103 103
104 if (state > PM_SUSPEND_ON) 104 if (state > PM_SUSPEND_ON) {
105 pm_wakep_autosleep_enabled(true);
105 queue_up_suspend_work(); 106 queue_up_suspend_work();
107 } else {
108 pm_wakep_autosleep_enabled(false);
109 }
106 110
107 mutex_unlock(&autosleep_lock); 111 mutex_unlock(&autosleep_lock);
108 return 0; 112 return 0;