aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/power/runtime.c
diff options
context:
space:
mode:
authorArjan van de Ven <arjan@linux.intel.com>2010-07-18 20:01:06 -0400
committerRafael J. Wysocki <rjw@sisk.pl>2010-07-18 20:01:06 -0400
commit8d4b9d1bfef117862a2889dec4dac227068544c9 (patch)
treea17f69a64b97759452988047058666ae51f70304 /drivers/base/power/runtime.c
parent0fcb4eef8294492c8f1de8236b1ed81f09e42922 (diff)
PM / Runtime: Add runtime PM statistics (v3)
In order for PowerTOP to be able to report how well the new runtime PM is working for the various drivers, the kernel needs to export some basic statistics in sysfs. This patch adds two sysfs files in the runtime PM domain that expose the total time a device has been active, and the time a device has been suspended. With this PowerTOP can compute the activity percentage Active %age = 100 * (delta active) / (delta active + delta suspended) and present the information to the user. I've written the PowerTOP code (slated for version 1.12) already, and the output looks like this: Runtime Device Power Management statistics Active Device name 10.0% 06:00.0 Ethernet controller: Realtek Semiconductor Co., Ltd. RTL8101E/RTL8102E PCI Express Fast Ethernet controller [version 2: fix stat update bugs noticed by Alan Stern] [version 3: rebase to -next and move the sysfs declaration] Signed-off-by: Arjan van de Ven <arjan@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl>
Diffstat (limited to 'drivers/base/power/runtime.c')
-rw-r--r--drivers/base/power/runtime.c54
1 files changed, 47 insertions, 7 deletions
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index b0ec0e9f27e..b78c401ffa7 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -123,6 +123,45 @@ int pm_runtime_idle(struct device *dev)
123} 123}
124EXPORT_SYMBOL_GPL(pm_runtime_idle); 124EXPORT_SYMBOL_GPL(pm_runtime_idle);
125 125
126
127/**
128 * update_pm_runtime_accounting - Update the time accounting of power states
129 * @dev: Device to update the accounting for
130 *
131 * In order to be able to have time accounting of the various power states
132 * (as used by programs such as PowerTOP to show the effectiveness of runtime
133 * PM), we need to track the time spent in each state.
134 * update_pm_runtime_accounting must be called each time before the
135 * runtime_status field is updated, to account the time in the old state
136 * correctly.
137 */
138void update_pm_runtime_accounting(struct device *dev)
139{
140 unsigned long now = jiffies;
141 int delta;
142
143 delta = now - dev->power.accounting_timestamp;
144
145 if (delta < 0)
146 delta = 0;
147
148 dev->power.accounting_timestamp = now;
149
150 if (dev->power.disable_depth > 0)
151 return;
152
153 if (dev->power.runtime_status == RPM_SUSPENDED)
154 dev->power.suspended_jiffies += delta;
155 else
156 dev->power.active_jiffies += delta;
157}
158
159static void __update_runtime_status(struct device *dev, enum rpm_status status)
160{
161 update_pm_runtime_accounting(dev);
162 dev->power.runtime_status = status;
163}
164
126/** 165/**
127 * __pm_runtime_suspend - Carry out run-time suspend of given device. 166 * __pm_runtime_suspend - Carry out run-time suspend of given device.
128 * @dev: Device to suspend. 167 * @dev: Device to suspend.
@@ -197,7 +236,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
197 goto repeat; 236 goto repeat;
198 } 237 }
199 238
200 dev->power.runtime_status = RPM_SUSPENDING; 239 __update_runtime_status(dev, RPM_SUSPENDING);
201 dev->power.deferred_resume = false; 240 dev->power.deferred_resume = false;
202 241
203 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) { 242 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_suspend) {
@@ -228,7 +267,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
228 } 267 }
229 268
230 if (retval) { 269 if (retval) {
231 dev->power.runtime_status = RPM_ACTIVE; 270 __update_runtime_status(dev, RPM_ACTIVE);
232 if (retval == -EAGAIN || retval == -EBUSY) { 271 if (retval == -EAGAIN || retval == -EBUSY) {
233 if (dev->power.timer_expires == 0) 272 if (dev->power.timer_expires == 0)
234 notify = true; 273 notify = true;
@@ -237,7 +276,7 @@ int __pm_runtime_suspend(struct device *dev, bool from_wq)
237 pm_runtime_cancel_pending(dev); 276 pm_runtime_cancel_pending(dev);
238 } 277 }
239 } else { 278 } else {
240 dev->power.runtime_status = RPM_SUSPENDED; 279 __update_runtime_status(dev, RPM_SUSPENDED);
241 pm_runtime_deactivate_timer(dev); 280 pm_runtime_deactivate_timer(dev);
242 281
243 if (dev->parent) { 282 if (dev->parent) {
@@ -381,7 +420,7 @@ int __pm_runtime_resume(struct device *dev, bool from_wq)
381 goto repeat; 420 goto repeat;
382 } 421 }
383 422
384 dev->power.runtime_status = RPM_RESUMING; 423 __update_runtime_status(dev, RPM_RESUMING);
385 424
386 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) { 425 if (dev->bus && dev->bus->pm && dev->bus->pm->runtime_resume) {
387 spin_unlock_irq(&dev->power.lock); 426 spin_unlock_irq(&dev->power.lock);
@@ -411,10 +450,10 @@ int __pm_runtime_resume(struct device *dev, bool from_wq)
411 } 450 }
412 451
413 if (retval) { 452 if (retval) {
414 dev->power.runtime_status = RPM_SUSPENDED; 453 __update_runtime_status(dev, RPM_SUSPENDED);
415 pm_runtime_cancel_pending(dev); 454 pm_runtime_cancel_pending(dev);
416 } else { 455 } else {
417 dev->power.runtime_status = RPM_ACTIVE; 456 __update_runtime_status(dev, RPM_ACTIVE);
418 if (parent) 457 if (parent)
419 atomic_inc(&parent->power.child_count); 458 atomic_inc(&parent->power.child_count);
420 } 459 }
@@ -848,7 +887,7 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status)
848 } 887 }
849 888
850 out_set: 889 out_set:
851 dev->power.runtime_status = status; 890 __update_runtime_status(dev, status);
852 dev->power.runtime_error = 0; 891 dev->power.runtime_error = 0;
853 out: 892 out:
854 spin_unlock_irqrestore(&dev->power.lock, flags); 893 spin_unlock_irqrestore(&dev->power.lock, flags);
@@ -1077,6 +1116,7 @@ void pm_runtime_init(struct device *dev)
1077 dev->power.request_pending = false; 1116 dev->power.request_pending = false;
1078 dev->power.request = RPM_REQ_NONE; 1117 dev->power.request = RPM_REQ_NONE;
1079 dev->power.deferred_resume = false; 1118 dev->power.deferred_resume = false;
1119 dev->power.accounting_timestamp = jiffies;
1080 INIT_WORK(&dev->power.work, pm_runtime_work); 1120 INIT_WORK(&dev->power.work, pm_runtime_work);
1081 1121
1082 dev->power.timer_expires = 0; 1122 dev->power.timer_expires = 0;