From patchwork Thu Aug 4 05:09:51 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Liu, ShuoX" X-Patchwork-Id: 1036672 Received: from smtp1.linux-foundation.org (smtp1.linux-foundation.org [140.211.169.13]) by demeter2.kernel.org (8.14.4/8.14.4) with ESMTP id p74INkQX001523 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=FAIL) for ; Thu, 4 Aug 2011 18:24:07 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 p74IMFFS007394; Thu, 4 Aug 2011 11:22:16 -0700 Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by smtp1.linux-foundation.org (8.14.2/8.13.5/Debian-3ubuntu1.1) with ESMTP id p745AgjR001101 for ; Wed, 3 Aug 2011 22:10:43 -0700 Received: from orsmga002.jf.intel.com ([10.7.209.21]) by orsmga101.jf.intel.com with ESMTP; 03 Aug 2011 22:10:42 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.67,315,1309762800"; d="scan'208,217,223";a="34214414" Received: from pgsmsx601.gar.corp.intel.com ([10.221.43.69]) by orsmga002.jf.intel.com with ESMTP; 03 Aug 2011 22:10:40 -0700 Received: from pgsmsx509.gar.corp.intel.com (172.30.13.17) by pgsmsx601.gar.corp.intel.com (10.221.43.69) with Microsoft SMTP Server (TLS) id 8.2.255.0; Thu, 4 Aug 2011 13:09:55 +0800 Received: from shsmsx601.ccr.corp.intel.com (10.239.4.112) by PGSMSX509.gar.corp.intel.com (172.30.13.17) with Microsoft SMTP Server (TLS) id 8.2.255.0; Thu, 4 Aug 2011 13:09:55 +0800 Received: from shsmsx502.ccr.corp.intel.com ([10.239.4.96]) by shsmsx601.ccr.corp.intel.com ([10.239.4.112]) with mapi; Thu, 4 Aug 2011 13:09:53 +0800 From: "Liu, ShuoX" To: "Brown, Len" , "pavel@ucw.cz" , "rjw@sisk.pl" , "gregkh@suse.de" Date: Thu, 4 Aug 2011 13:09:51 +0800 Thread-Topic: [PATCH] PM: add statistics sysfs file for suspend to ram Thread-Index: AcxSZL0p0InZQ3baQRu+NvbMVCb5TQ== Message-ID: <6E3BC7F7C9A4BF4286DD4C043110F30B5B790E573B@shsmsx502.ccr.corp.intel.com> Accept-Language: zh-CN, en-US Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: acceptlanguage: zh-CN, en-US MIME-Version: 1.0 Received-SPF: pass (localhost is always allowed.) X-Spam-Status: No, hits=-106.645 required=5 tests=AWL, BAYES_00, HTML_MESSAGE, OSDL_HEADER_SUBJECT_BRACKETED, PATCH_SUBJECT_OSDL, USER_IN_WHITELIST 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 X-Mailman-Approved-At: Thu, 04 Aug 2011 11:21:43 -0700 Cc: "linux-pm@lists.linux-foundation.org" Subject: [linux-pm] [PATCH] PM: add statistics sysfs file for suspend to ram 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 (demeter2.kernel.org [140.211.167.43]); Thu, 04 Aug 2011 18:24:07 +0000 (UTC) From a906b0b5b4ff3414ceb9fc7a69a3d7c9d66e46b1 Mon Sep 17 00:00:00 2001 From: ShuoX Liu Date: Thu, 28 Jul 2011 10:54:22 +0800 Subject: [PATCH] PM: add statistics sysfs file for suspend to ram. Record S3 failure time about each reason and the latest two failed devices' name in S3 progress. We can check it through /sys/power/suspend_stats. Change-Id: Ieed7fd74e27d3b482675a20cb0bb26b9054a1624 Signed-off-by: ShuoX Liu --- drivers/base/power/main.c | 31 +++++++++++++++++++++++++-- include/linux/suspend.h | 16 ++++++++++++++ kernel/power/main.c | 49 +++++++++++++++++++++++++++++++++++++++++++++ kernel/power/suspend.c | 13 ++++++++++- 4 files changed, 104 insertions(+), 5 deletions(-) -- 1.7.1 diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index a854591..da1c561 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c @@ -46,6 +46,7 @@ LIST_HEAD(dpm_prepared_list); LIST_HEAD(dpm_suspended_list); LIST_HEAD(dpm_noirq_list); +struct suspend_stats suspend_stats; static DEFINE_MUTEX(dpm_list_mtx); static pm_message_t pm_transition; @@ -180,6 +181,15 @@ static void initcall_debug_report(struct device *dev, ktime_t calltime, } } +static void dpm_save_dev_name(const char *name) +{ + strlcpy(suspend_stats.failed_devs[suspend_stats.last_failed], + name, + sizeof(suspend_stats.failed_devs[0])); + suspend_stats.last_failed++; + suspend_stats.last_failed %= REC_FAILED_DEV_NUM; +} + /** * dpm_wait - Wait for a PM operation to complete. * @dev: Device to wait for. @@ -464,8 +474,11 @@ void dpm_resume_noirq(pm_message_t state) mutex_unlock(&dpm_list_mtx); error = device_resume_noirq(dev, state); - if (error) + if (error) { + suspend_stats.failed_resume_noirq++; + dpm_save_dev_name(dev_name(dev)); pm_dev_err(dev, state, " early", error); + } mutex_lock(&dpm_list_mtx); put_device(dev); @@ -626,8 +639,11 @@ void dpm_resume(pm_message_t state) mutex_unlock(&dpm_list_mtx); error = device_resume(dev, state, false); - if (error) + if (error) { + suspend_stats.failed_resume++; + dpm_save_dev_name(dev_name(dev)); pm_dev_err(dev, state, "", error); + } mutex_lock(&dpm_list_mtx); } @@ -802,6 +818,8 @@ int dpm_suspend_noirq(pm_message_t state) mutex_lock(&dpm_list_mtx); if (error) { pm_dev_err(dev, state, " late", error); + suspend_stats.failed_suspend_noirq++; + dpm_save_dev_name(dev_name(dev)); put_device(dev); break; } @@ -923,8 +941,10 @@ static void async_suspend(void *data, async_cookie_t cookie) int error; error = __device_suspend(dev, pm_transition, true); - if (error) + if (error) { + dpm_save_dev_name(dev_name(dev)); pm_dev_err(dev, pm_transition, " async", error); + } put_device(dev); } @@ -967,6 +987,7 @@ int dpm_suspend(pm_message_t state) mutex_lock(&dpm_list_mtx); if (error) { pm_dev_err(dev, state, "", error); + dpm_save_dev_name(dev_name(dev)); put_device(dev); break; } @@ -982,6 +1003,8 @@ int dpm_suspend(pm_message_t state) error = async_error; if (!error) dpm_show_time(starttime, state, NULL); + else + suspend_stats.failed_suspend++; return error; } @@ -1090,6 +1113,8 @@ int dpm_suspend_start(pm_message_t state) error = dpm_prepare(state); if (!error) error = dpm_suspend(state); + else + suspend_stats.failed_prepare++; return error; } EXPORT_SYMBOL_GPL(dpm_suspend_start); diff --git a/include/linux/suspend.h b/include/linux/suspend.h index 6bbcef2..6a8ff23 100644 --- a/include/linux/suspend.h +++ b/include/linux/suspend.h @@ -34,6 +34,22 @@ typedef int __bitwise suspend_state_t; #define PM_SUSPEND_MEM ((__force suspend_state_t) 3) #define PM_SUSPEND_MAX ((__force suspend_state_t) 4) +struct suspend_stats { + int success; + int fail; + int failed_freeze; + int failed_prepare; + int failed_suspend; + int failed_suspend_noirq; + int failed_resume; + int failed_resume_noirq; +#define REC_FAILED_DEV_NUM 2 + char failed_devs[REC_FAILED_DEV_NUM][40]; + int last_failed; +}; + +extern struct suspend_stats suspend_stats; + /** * struct platform_suspend_ops - Callbacks for managing platform dependent * system sleep states. diff --git a/kernel/power/main.c b/kernel/power/main.c index 6c601f8..32eb67b 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -133,6 +133,50 @@ power_attr(pm_test); #endif /* CONFIG_PM_SLEEP */ +static ssize_t suspend_stats_show(struct kobject *kobj, + struct kobj_attribute *attr, char *buf) +{ + int i, index, last_index; + char *s = buf; + + last_index = suspend_stats.last_failed + REC_FAILED_DEV_NUM - 1; + last_index %= REC_FAILED_DEV_NUM; + s += sprintf(s, "%s: %d\n%s: %d\n%s: %d\n%s: %d\n" + "%s: %d\n%s: %d\n%s: %d\n%s: %d\n", + "success", suspend_stats.success, + "fail", suspend_stats.fail, + "failed_freeze", suspend_stats.failed_freeze, + "failed_prepare", suspend_stats.failed_prepare, + "failed_suspend", suspend_stats.failed_suspend, + "failed_suspend_noirq", + suspend_stats.failed_suspend_noirq, + "failed_resume", suspend_stats.failed_resume, + "failed_resume_noirq", + suspend_stats.failed_resume_noirq); + s += sprintf(s, "failed_devs:\n last_failed:\t%s\n", + suspend_stats.failed_devs[last_index]); + for (i = 1; i < REC_FAILED_DEV_NUM; i++) { + index = last_index + REC_FAILED_DEV_NUM - i; + index %= REC_FAILED_DEV_NUM; + s += sprintf(s, "\t\t%s\n", + suspend_stats.failed_devs[index]); + } + + if (s != buf) + /* convert the last space to a newline */ + *(s-1) = '\n'; + + return s - buf; +} + +static ssize_t suspend_stats_store(struct kobject *kobj, + struct kobj_attribute *attr, const char *buf, size_t n) +{ + return n; +} + +power_attr(suspend_stats); + struct kobject *power_kobj; /** @@ -194,6 +238,10 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, } if (state < PM_SUSPEND_MAX && *s) error = enter_state(state); + if (error) + suspend_stats.fail++; + else + suspend_stats.success++; #endif Exit: @@ -310,6 +358,7 @@ static struct attribute * g[] = { #ifdef CONFIG_PM_DEBUG &pm_test_attr.attr, #endif + &suspend_stats_attr.attr, #endif NULL, }; diff --git a/kernel/power/suspend.c b/kernel/power/suspend.c index b6b71ad..9bb4281 100644 --- a/kernel/power/suspend.c +++ b/kernel/power/suspend.c @@ -106,6 +106,8 @@ static int suspend_prepare(void) error = suspend_freeze_processes(); if (!error) return 0; + else + suspend_stats.failed_freeze++; suspend_thaw_processes(); usermodehelper_enable(); @@ -315,8 +317,15 @@ int enter_state(suspend_state_t state) */ int pm_suspend(suspend_state_t state) { - if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX) - return enter_state(state); + int ret; + if (state > PM_SUSPEND_ON && state <= PM_SUSPEND_MAX) { + ret = enter_state(state); + if (ret) + suspend_stats.fail++; + else + suspend_stats.success++; + return ret; + } return -EINVAL; } EXPORT_SYMBOL(pm_suspend);