aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2012-04-29 16:52:52 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2012-05-01 15:25:11 -0400
commit30e3ce6dcbe3fc29c343b17e768b07d4a795de21 (patch)
tree42af32f901aab0c9cbca0dc22f755f9fe3936d67
parent60af1066913162c5dd13fad3b872a67b1eb7da0f (diff)
PM / Sleep: Change wakeup source statistics to follow Android
Wakeup statistics used by Android are slightly different from what we have in wakeup sources at the moment and there aren't any known users of those statistics other than Android, so modify them to make it easier for Android to switch to wakeup sources. This removes the struct wakeup_source's hit_cout field, which is very rough and therefore not very useful, and adds two new fields, wakeup_count and expire_count. The first one tracks how many times the wakeup source is activated with events_check_enabled set (which roughly corresponds to the situations when a system power transition to a sleep state is in progress and would be aborted by this wakeup source if it were the only active one at that time) and the second one is the number of times the wakeup source has been activated with a timeout that expired. Additionally, the last_time field is now updated when the wakeup source is deactivated too (previously it was only updated during the wakeup source's activation), which seems to be what Android does with the analogous counter for wakelocks. 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-power24
-rw-r--r--drivers/base/power/sysfs.c30
-rw-r--r--drivers/base/power/wakeup.c64
-rw-r--r--include/linux/pm_wakeup.h11
4 files changed, 77 insertions, 52 deletions
diff --git a/Documentation/ABI/testing/sysfs-devices-power b/Documentation/ABI/testing/sysfs-devices-power
index 840f7d64d483..b0a5d9a6135e 100644
--- a/Documentation/ABI/testing/sysfs-devices-power
+++ b/Documentation/ABI/testing/sysfs-devices-power
@@ -96,16 +96,26 @@ Description:
96 is read-only. If the device is not enabled to wake up the 96 is read-only. If the device is not enabled to wake up the
97 system from sleep states, this attribute is not present. 97 system from sleep states, this attribute is not present.
98 98
99What: /sys/devices/.../power/wakeup_hit_count 99What: /sys/devices/.../power/wakeup_abort_count
100Date: September 2010 100Date: February 2012
101Contact: Rafael J. Wysocki <rjw@sisk.pl> 101Contact: Rafael J. Wysocki <rjw@sisk.pl>
102Description: 102Description:
103 The /sys/devices/.../wakeup_hit_count attribute contains the 103 The /sys/devices/.../wakeup_abort_count attribute contains the
104 number of times the processing of a wakeup event associated with 104 number of times the processing of a wakeup event associated with
105 the device might prevent the system from entering a sleep state. 105 the device might have aborted system transition into a sleep
106 This attribute is read-only. If the device is not enabled to 106 state in progress. This attribute is read-only. If the device
107 wake up the system from sleep states, this attribute is not 107 is not enabled to wake up the system from sleep states, this
108 present. 108 attribute is not present.
109
110What: /sys/devices/.../power/wakeup_expire_count
111Date: February 2012
112Contact: Rafael J. Wysocki <rjw@sisk.pl>
113Description:
114 The /sys/devices/.../wakeup_expire_count attribute contains the
115 number of times a wakeup event associated with the device has
116 been reported with a timeout that expired. This attribute is
117 read-only. If the device is not enabled to wake up the system
118 from sleep states, this attribute is not present.
109 119
110What: /sys/devices/.../power/wakeup_active 120What: /sys/devices/.../power/wakeup_active
111Date: September 2010 121Date: September 2010
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index 95c12f6cb5b9..13e40b9021b9 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -314,22 +314,41 @@ static ssize_t wakeup_active_count_show(struct device *dev,
314 314
315static DEVICE_ATTR(wakeup_active_count, 0444, wakeup_active_count_show, NULL); 315static DEVICE_ATTR(wakeup_active_count, 0444, wakeup_active_count_show, NULL);
316 316
317static ssize_t wakeup_hit_count_show(struct device *dev, 317static ssize_t wakeup_abort_count_show(struct device *dev,
318 struct device_attribute *attr, char *buf) 318 struct device_attribute *attr,
319 char *buf)
320{
321 unsigned long count = 0;
322 bool enabled = false;
323
324 spin_lock_irq(&dev->power.lock);
325 if (dev->power.wakeup) {
326 count = dev->power.wakeup->wakeup_count;
327 enabled = true;
328 }
329 spin_unlock_irq(&dev->power.lock);
330 return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
331}
332
333static DEVICE_ATTR(wakeup_abort_count, 0444, wakeup_abort_count_show, NULL);
334
335static ssize_t wakeup_expire_count_show(struct device *dev,
336 struct device_attribute *attr,
337 char *buf)
319{ 338{
320 unsigned long count = 0; 339 unsigned long count = 0;
321 bool enabled = false; 340 bool enabled = false;
322 341
323 spin_lock_irq(&dev->power.lock); 342 spin_lock_irq(&dev->power.lock);
324 if (dev->power.wakeup) { 343 if (dev->power.wakeup) {
325 count = dev->power.wakeup->hit_count; 344 count = dev->power.wakeup->expire_count;
326 enabled = true; 345 enabled = true;
327 } 346 }
328 spin_unlock_irq(&dev->power.lock); 347 spin_unlock_irq(&dev->power.lock);
329 return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n"); 348 return enabled ? sprintf(buf, "%lu\n", count) : sprintf(buf, "\n");
330} 349}
331 350
332static DEVICE_ATTR(wakeup_hit_count, 0444, wakeup_hit_count_show, NULL); 351static DEVICE_ATTR(wakeup_expire_count, 0444, wakeup_expire_count_show, NULL);
333 352
334static ssize_t wakeup_active_show(struct device *dev, 353static ssize_t wakeup_active_show(struct device *dev,
335 struct device_attribute *attr, char *buf) 354 struct device_attribute *attr, char *buf)
@@ -486,7 +505,8 @@ static struct attribute *wakeup_attrs[] = {
486 &dev_attr_wakeup.attr, 505 &dev_attr_wakeup.attr,
487 &dev_attr_wakeup_count.attr, 506 &dev_attr_wakeup_count.attr,
488 &dev_attr_wakeup_active_count.attr, 507 &dev_attr_wakeup_active_count.attr,
489 &dev_attr_wakeup_hit_count.attr, 508 &dev_attr_wakeup_abort_count.attr,
509 &dev_attr_wakeup_expire_count.attr,
490 &dev_attr_wakeup_active.attr, 510 &dev_attr_wakeup_active.attr,
491 &dev_attr_wakeup_total_time_ms.attr, 511 &dev_attr_wakeup_total_time_ms.attr,
492 &dev_attr_wakeup_max_time_ms.attr, 512 &dev_attr_wakeup_max_time_ms.attr,
diff --git a/drivers/base/power/wakeup.c b/drivers/base/power/wakeup.c
index 92f220d89d35..7a6eada4534d 100644
--- a/drivers/base/power/wakeup.c
+++ b/drivers/base/power/wakeup.c
@@ -21,7 +21,7 @@
21 * If set, the suspend/hibernate code will abort transitions to a sleep state 21 * If set, the suspend/hibernate code will abort transitions to a sleep state
22 * if wakeup events are registered during or immediately before the transition. 22 * if wakeup events are registered during or immediately before the transition.
23 */ 23 */
24bool events_check_enabled; 24bool events_check_enabled __read_mostly;
25 25
26/* 26/*
27 * Combined counters of registered wakeup events and wakeup events in progress. 27 * Combined counters of registered wakeup events and wakeup events in progress.
@@ -383,6 +383,21 @@ static void wakeup_source_activate(struct wakeup_source *ws)
383} 383}
384 384
385/** 385/**
386 * wakeup_source_report_event - Report wakeup event using the given source.
387 * @ws: Wakeup source to report the event for.
388 */
389static void wakeup_source_report_event(struct wakeup_source *ws)
390{
391 ws->event_count++;
392 /* This is racy, but the counter is approximate anyway. */
393 if (events_check_enabled)
394 ws->wakeup_count++;
395
396 if (!ws->active)
397 wakeup_source_activate(ws);
398}
399
400/**
386 * __pm_stay_awake - Notify the PM core of a wakeup event. 401 * __pm_stay_awake - Notify the PM core of a wakeup event.
387 * @ws: Wakeup source object associated with the source of the event. 402 * @ws: Wakeup source object associated with the source of the event.
388 * 403 *
@@ -397,10 +412,7 @@ void __pm_stay_awake(struct wakeup_source *ws)
397 412
398 spin_lock_irqsave(&ws->lock, flags); 413 spin_lock_irqsave(&ws->lock, flags);
399 414
400 ws->event_count++; 415 wakeup_source_report_event(ws);
401 if (!ws->active)
402 wakeup_source_activate(ws);
403
404 del_timer(&ws->timer); 416 del_timer(&ws->timer);
405 ws->timer_expires = 0; 417 ws->timer_expires = 0;
406 418
@@ -469,6 +481,7 @@ static void wakeup_source_deactivate(struct wakeup_source *ws)
469 if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time)) 481 if (ktime_to_ns(duration) > ktime_to_ns(ws->max_time))
470 ws->max_time = duration; 482 ws->max_time = duration;
471 483
484 ws->last_time = now;
472 del_timer(&ws->timer); 485 del_timer(&ws->timer);
473 ws->timer_expires = 0; 486 ws->timer_expires = 0;
474 487
@@ -541,8 +554,10 @@ static void pm_wakeup_timer_fn(unsigned long data)
541 spin_lock_irqsave(&ws->lock, flags); 554 spin_lock_irqsave(&ws->lock, flags);
542 555
543 if (ws->active && ws->timer_expires 556 if (ws->active && ws->timer_expires
544 && time_after_eq(jiffies, ws->timer_expires)) 557 && time_after_eq(jiffies, ws->timer_expires)) {
545 wakeup_source_deactivate(ws); 558 wakeup_source_deactivate(ws);
559 ws->expire_count++;
560 }
546 561
547 spin_unlock_irqrestore(&ws->lock, flags); 562 spin_unlock_irqrestore(&ws->lock, flags);
548} 563}
@@ -569,9 +584,7 @@ void __pm_wakeup_event(struct wakeup_source *ws, unsigned int msec)
569 584
570 spin_lock_irqsave(&ws->lock, flags); 585 spin_lock_irqsave(&ws->lock, flags);
571 586
572 ws->event_count++; 587 wakeup_source_report_event(ws);
573 if (!ws->active)
574 wakeup_source_activate(ws);
575 588
576 if (!msec) { 589 if (!msec) {
577 wakeup_source_deactivate(ws); 590 wakeup_source_deactivate(ws);
@@ -614,24 +627,6 @@ void pm_wakeup_event(struct device *dev, unsigned int msec)
614EXPORT_SYMBOL_GPL(pm_wakeup_event); 627EXPORT_SYMBOL_GPL(pm_wakeup_event);
615 628
616/** 629/**
617 * pm_wakeup_update_hit_counts - Update hit counts of all active wakeup sources.
618 */
619static void pm_wakeup_update_hit_counts(void)
620{
621 unsigned long flags;
622 struct wakeup_source *ws;
623
624 rcu_read_lock();
625 list_for_each_entry_rcu(ws, &wakeup_sources, entry) {
626 spin_lock_irqsave(&ws->lock, flags);
627 if (ws->active)
628 ws->hit_count++;
629 spin_unlock_irqrestore(&ws->lock, flags);
630 }
631 rcu_read_unlock();
632}
633
634/**
635 * pm_wakeup_pending - Check if power transition in progress should be aborted. 630 * pm_wakeup_pending - Check if power transition in progress should be aborted.
636 * 631 *
637 * Compare the current number of registered wakeup events with its preserved 632 * Compare the current number of registered wakeup events with its preserved
@@ -653,8 +648,6 @@ bool pm_wakeup_pending(void)
653 events_check_enabled = !ret; 648 events_check_enabled = !ret;
654 } 649 }
655 spin_unlock_irqrestore(&events_lock, flags); 650 spin_unlock_irqrestore(&events_lock, flags);
656 if (ret)
657 pm_wakeup_update_hit_counts();
658 return ret; 651 return ret;
659} 652}
660 653
@@ -680,7 +673,6 @@ bool pm_get_wakeup_count(unsigned int *count)
680 split_counters(&cnt, &inpr); 673 split_counters(&cnt, &inpr);
681 if (inpr == 0 || signal_pending(current)) 674 if (inpr == 0 || signal_pending(current))
682 break; 675 break;
683 pm_wakeup_update_hit_counts();
684 676
685 schedule(); 677 schedule();
686 } 678 }
@@ -713,8 +705,6 @@ bool pm_save_wakeup_count(unsigned int count)
713 events_check_enabled = true; 705 events_check_enabled = true;
714 } 706 }
715 spin_unlock_irq(&events_lock); 707 spin_unlock_irq(&events_lock);
716 if (!events_check_enabled)
717 pm_wakeup_update_hit_counts();
718 return events_check_enabled; 708 return events_check_enabled;
719} 709}
720 710
@@ -749,9 +739,10 @@ static int print_wakeup_source_stats(struct seq_file *m,
749 active_time = ktime_set(0, 0); 739 active_time = ktime_set(0, 0);
750 } 740 }
751 741
752 ret = seq_printf(m, "%-12s\t%lu\t\t%lu\t\t%lu\t\t" 742 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", 743 "%lld\t\t%lld\t\t%lld\t\t%lld\n",
754 ws->name, active_count, ws->event_count, ws->hit_count, 744 ws->name, active_count, ws->event_count,
745 ws->wakeup_count, ws->expire_count,
755 ktime_to_ms(active_time), ktime_to_ms(total_time), 746 ktime_to_ms(active_time), ktime_to_ms(total_time),
756 ktime_to_ms(max_time), ktime_to_ms(ws->last_time)); 747 ktime_to_ms(max_time), ktime_to_ms(ws->last_time));
757 748
@@ -768,8 +759,9 @@ static int wakeup_sources_stats_show(struct seq_file *m, void *unused)
768{ 759{
769 struct wakeup_source *ws; 760 struct wakeup_source *ws;
770 761
771 seq_puts(m, "name\t\tactive_count\tevent_count\thit_count\t" 762 seq_puts(m, "name\t\tactive_count\tevent_count\twakeup_count\t"
772 "active_since\ttotal_time\tmax_time\tlast_change\n"); 763 "expire_count\tactive_since\ttotal_time\tmax_time\t"
764 "last_change\n");
773 765
774 rcu_read_lock(); 766 rcu_read_lock();
775 list_for_each_entry_rcu(ws, &wakeup_sources, entry) 767 list_for_each_entry_rcu(ws, &wakeup_sources, entry)
diff --git a/include/linux/pm_wakeup.h b/include/linux/pm_wakeup.h
index d9f05113e5fb..5285317a612a 100644
--- a/include/linux/pm_wakeup.h
+++ b/include/linux/pm_wakeup.h
@@ -33,12 +33,14 @@
33 * 33 *
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 activated last time. 36 * @last_time: Monotonic clock when the wakeup source's was touched last time.
37 * @event_count: Number of signaled wakeup events. 37 * @event_count: Number of signaled wakeup events.
38 * @active_count: Number of times the wakeup sorce was activated. 38 * @active_count: Number of times the wakeup sorce was activated.
39 * @relax_count: Number of times the wakeup sorce was deactivated. 39 * @relax_count: Number of times the wakeup sorce was deactivated.
40 * @hit_count: Number of times the wakeup sorce might abort system suspend. 40 * @expire_count: Number of times the wakeup source's timeout has expired.
41 * @wakeup_count: Number of times the wakeup source might abort suspend.
41 * @active: Status of the wakeup source. 42 * @active: Status of the wakeup source.
43 * @has_timeout: The wakeup source has been activated with a timeout.
42 */ 44 */
43struct wakeup_source { 45struct wakeup_source {
44 const char *name; 46 const char *name;
@@ -52,8 +54,9 @@ struct wakeup_source {
52 unsigned long event_count; 54 unsigned long event_count;
53 unsigned long active_count; 55 unsigned long active_count;
54 unsigned long relax_count; 56 unsigned long relax_count;
55 unsigned long hit_count; 57 unsigned long expire_count;
56 unsigned int active:1; 58 unsigned long wakeup_count;
59 bool active:1;
57}; 60};
58 61
59#ifdef CONFIG_PM_SLEEP 62#ifdef CONFIG_PM_SLEEP