diff options
author | Rafael J. Wysocki <rjw@sisk.pl> | 2012-04-29 16:53:32 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rjw@sisk.pl> | 2012-05-01 15:25:49 -0400 |
commit | 55850945e872531644f31fefd217d61dd15dcab8 (patch) | |
tree | 412ee1338d0b69e4d6e2a5e518e30e6660704921 /drivers/base | |
parent | 7483b4a4d9abf9dcf1ffe6e805ead2847ec3264e (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>
Diffstat (limited to 'drivers/base')
-rw-r--r-- | drivers/base/power/sysfs.c | 24 | ||||
-rw-r--r-- | drivers/base/power/wakeup.c | 61 |
2 files changed, 81 insertions, 4 deletions
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 | ||
419 | static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL); | 419 | static DEVICE_ATTR(wakeup_last_time_ms, 0444, wakeup_last_time_show, NULL); |
420 | |||
421 | #ifdef CONFIG_PM_AUTOSLEEP | ||
422 | static 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 | |||
438 | static 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 | } |
450 | EXPORT_SYMBOL_GPL(pm_stay_awake); | 452 | EXPORT_SYMBOL_GPL(pm_stay_awake); |
451 | 453 | ||
454 | #ifdef CONFIG_PM_AUTOSLEEP | ||
455 | static 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 | ||
461 | static 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 | */ | ||
742 | void 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 | |||
721 | static struct dentry *wakeup_sources_stats_dentry; | 765 | static 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) |