From patchwork Thu Apr 7 12:54:54 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "JieJing.Zhang" X-Patchwork-Id: 692371 Received: from smtp1.linux-foundation.org (smtp1.linux-foundation.org [140.211.169.13]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id p37D0p7l027761 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Thu, 7 Apr 2011 13:01:16 GMT Received: from daredevil.linux-foundation.org (localhost [127.0.0.1]) by smtp1.linux-foundation.org (8.14.2/8.13.5/Debian-3ubuntu1.1) with ESMTP id p37Cw3in012415; Thu, 7 Apr 2011 05:58:31 -0700 Received: from mail-iw0-f175.google.com (mail-iw0-f175.google.com [209.85.214.175]) by smtp1.linux-foundation.org (8.14.2/8.13.5/Debian-3ubuntu1.1) with ESMTP id p37Ctm1O012197 (version=TLSv1/SSLv3 cipher=RC4-SHA bits=128 verify=FAIL) for ; Thu, 7 Apr 2011 05:55:50 -0700 Received: by iwn10 with SMTP id 10so2655748iwn.6 for ; Thu, 07 Apr 2011 05:55:48 -0700 (PDT) Received: by 10.42.26.83 with SMTP id e19mr1335539icc.387.1302180948196; Thu, 07 Apr 2011 05:55:48 -0700 (PDT) Received: from localhost.localdomain ([116.227.98.218]) by mx.google.com with ESMTPS id g16sm1144577ibb.20.2011.04.07.05.55.40 (version=TLSv1/SSLv3 cipher=OTHER); Thu, 07 Apr 2011 05:55:47 -0700 (PDT) From: Jiejing Zhang To: Len Brown , Pavel Machek , "Rafael J. Wysocki" , Greg Kroah-Hartman , linux-pm@lists.linux-foundation.org, linux-kernel@vger.kernel.org Date: Thu, 7 Apr 2011 20:54:54 +0800 Message-Id: <1302180894-16468-1-git-send-email-kzjeef@gmail.com> X-Mailer: git-send-email 1.7.1 Received-SPF: pass (localhost is always allowed.) X-Spam-Status: No, hits=-5.125 required=5 tests=AWL, BAYES_00, OSDL_HEADER_SPF_PASS, OSDL_HEADER_SUBJECT_BRACKETED X-Spam-Checker-Version: SpamAssassin 3.2.4-osdl_revision__1.47__ X-MIMEDefang-Filter: lf$Revision: 1.188 $ X-Scanned-By: MIMEDefang 2.63 on 140.211.169.21 Cc: Zhang Jiejing Subject: [linux-pm] [RESEND PATCH] PM: add a config that give warnning if driver take too long on suspend/resume. X-BeenThere: linux-pm@lists.linux-foundation.org X-Mailman-Version: 2.1.9 Precedence: list List-Id: Linux power management List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-pm-bounces@lists.linux-foundation.org Errors-To: linux-pm-bounces@lists.linux-foundation.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Thu, 07 Apr 2011 13:01:18 +0000 (UTC) From: Zhang Jiejing This patch add function to check each device's suspend time consumption. If any driver takes more time that the threshold (default 0.5 ms), it will print a warnning message including the device and bus name on the console. You can change the threshold on-the-fly by modify file '/sys/power/device_suspend_time_threshold' to adjust this value,the unit is in microsecond. The output is like: PM: device (bus) :(device name) suspend/resume too slow, takes (time) msencs. PM: device platform:soc-audio.2 suspend too slow, takes 606.696 msecs PM: device platform:mxc_sdc_fb.1 suspend too slow, takes 7.708 msecs Signed-off-by: Zhang Jiejing --- drivers/base/power/main.c | 40 +++++++++++++++++++++++++++++++++++++++- drivers/base/power/power.h | 3 +++ kernel/power/Kconfig | 15 +++++++++++++++ kernel/power/main.c | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 1 deletions(-) diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 052dc53..000243c 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -178,6 +178,40 @@ static void initcall_debug_report(struct device *dev, ktime_t calltime, } } +#ifdef CONFIG_SUSPEND_DEVICE_TIME_DEBUG +static void suspend_time_debug_start(ktime_t *start) +{ + *start = ktime_get(); +} + +static void suspend_time_debug_report(const char *name, struct device *dev, + ktime_t starttime) +{ + ktime_t rettime; + s64 usecs64; + int usecs; + + if (!dev->driver) + return; + + rettime = ktime_get(); + usecs64 = ktime_to_us(ktime_sub(rettime, starttime)); + usecs = usecs64; + if (usecs == 0) + usecs = 1; + + if (device_suspend_time_threshold + && usecs > device_suspend_time_threshold) + pr_info("PM: device %s:%s %s too slow, it takes \t %ld.%03ld mses\n", + dev->bus->name, dev_name(dev), name, + usecs / USEC_PER_MSEC, usecs % USEC_PER_MSEC); +} +#else +static void suspend_time_debug_start(ktime_t *start) {} +static void suspend_time_debug_report(const char *name, struct device *dev, + ktime_t starttime) {} +#endif /* CONFIG_SUSPEND_DEVICE_TIME_DEBUG */ + /** * dpm_wait - Wait for a PM operation to complete. * @dev: Device to wait for. @@ -214,7 +248,7 @@ static int pm_op(struct device *dev, pm_message_t state) { int error = 0; - ktime_t calltime; + ktime_t calltime, starttime; calltime = initcall_debug_start(dev); @@ -222,13 +256,17 @@ static int pm_op(struct device *dev, #ifdef CONFIG_SUSPEND case PM_EVENT_SUSPEND: if (ops->suspend) { + suspend_time_debug_start(&starttime); error = ops->suspend(dev); + suspend_time_debug_report("suspend", dev, starttime); suspend_report_result(ops->suspend, error); } break; case PM_EVENT_RESUME: if (ops->resume) { + suspend_time_debug_start(&starttime); error = ops->resume(dev); + suspend_time_debug_report("resume", dev, starttime); suspend_report_result(ops->resume, error); } break; diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h index f2a25f1..72d5963 100644 --- a/drivers/base/power/power.h +++ b/drivers/base/power/power.h @@ -18,6 +18,9 @@ extern int pm_async_enabled; /* drivers/base/power/main.c */ extern struct list_head dpm_list; /* The active device list */ +/* driver/base/power/main.c */ +extern int device_suspend_time_threshold; + static inline struct device *to_device(struct list_head *entry) { return container_of(entry, struct device, power.entry); diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 4603f08..9b82c4b 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -87,6 +87,21 @@ config PM_SLEEP def_bool y depends on SUSPEND || HIBERNATION || XEN_SAVE_RESTORE +config SUSPEND_DEVICE_TIME_DEBUG + bool "Warnning device suspend/resume takes too much time" + depends on SUSPEND && PM_DEBUG + default n + ---help--- + + This option will enable a timing function to check each device + suspend time consumption, If the device takes more time that + the threshold (default 0.5 ms), it will print the device and + bus name on the console. You can change the threshold + on-the-fly by modify "/sys/power/device_suspend_time_threshold" + the unit is in microsecond. + + This options only for debug proprose, If in doubt, say N. + config PM_SLEEP_SMP def_bool y depends on SMP diff --git a/kernel/power/main.c b/kernel/power/main.c index 8eaba5f..d2e734f 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -297,12 +297,44 @@ power_attr(pm_trace_dev_match); #endif /* CONFIG_PM_TRACE */ +#ifdef CONFIG_SUSPEND_DEVICE_TIME_DEBUG +/* + * threshold of device suspend time consumption in microsecond(0.5ms), the + * driver suspend/resume time longer than this threshold will be + * print to console, 0 to disable */ +int device_suspend_time_threshold = 500; + +static ssize_t +device_suspend_time_threshold_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + return sprintf(buf, "%d\n", device_suspend_time_threshold); +} + +static ssize_t +device_suspend_time_threshold_store(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + int val; + if (sscanf(buf, "%d", &val) > 0) { + device_suspend_time_threshold = val; + return n; + } + return -EINVAL; +} +power_attr(device_suspend_time_threshold); +#endif + static struct attribute * g[] = { &state_attr.attr, #ifdef CONFIG_PM_TRACE &pm_trace_attr.attr, &pm_trace_dev_match_attr.attr, #endif +#ifdef CONFIG_SUSPEND_DEVICE_TIME_DEBUG + &device_suspend_time_threshold_attr.attr, +#endif #ifdef CONFIG_PM_SLEEP &pm_async_attr.attr, &wakeup_count_attr.attr,