All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] PM: add statistics sysfs file for suspend to ram
@ 2011-08-04  5:09 Liu, ShuoX
  2011-08-04  5:16 ` Greg KH
  2011-08-04  5:17 ` Greg KH
  0 siblings, 2 replies; 22+ messages in thread
From: Liu, ShuoX @ 2011-08-04  5:09 UTC (permalink / raw)
  To: Brown, Len, pavel, rjw, gregkh; +Cc: linux-pm


[-- Attachment #1.1: Type: text/plain, Size: 7944 bytes --]

>From a906b0b5b4ff3414ceb9fc7a69a3d7c9d66e46b1 Mon Sep 17 00:00:00 2001
From: ShuoX Liu <shuox.liu@intel.com>
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 <shuox.liu@intel.com>
---
 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(-)

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);
--
1.7.1



[-- Attachment #1.2: Type: text/html, Size: 16111 bytes --]

[-- Attachment #2: Type: text/plain, Size: 0 bytes --]



^ permalink raw reply related	[flat|nested] 22+ messages in thread
* [PATCH] PM: add statistics sysfs file for suspend to ram
@ 2011-08-04  5:13 Liu, ShuoX
  2011-08-04  5:27 ` Greg KH
  2011-08-04 19:05 ` Len Brown
  0 siblings, 2 replies; 22+ messages in thread
From: Liu, ShuoX @ 2011-08-04  5:13 UTC (permalink / raw)
  To: Brown, Len, pavel, rjw, gregkh; +Cc: linux-pm

>From a906b0b5b4ff3414ceb9fc7a69a3d7c9d66e46b1 Mon Sep 17 00:00:00 2001
From: ShuoX Liu <shuox.liu@intel.com>
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 <shuox.liu@intel.com>
---
 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(-)

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);
-- 
1.7.1

^ permalink raw reply related	[flat|nested] 22+ messages in thread

end of thread, other threads:[~2011-08-11 19:48 UTC | newest]

Thread overview: 22+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-08-04  5:09 [PATCH] PM: add statistics sysfs file for suspend to ram Liu, ShuoX
2011-08-04  5:16 ` Greg KH
2011-08-04  5:17 ` Greg KH
2011-08-03 17:37   ` Pavel Machek
2011-08-04  5:13 Liu, ShuoX
2011-08-04  5:27 ` Greg KH
2011-08-04  9:32   ` Rafael J. Wysocki
2011-08-05  1:57     ` Liu, ShuoX
2011-08-05  3:19       ` Yanmin Zhang
2011-08-05 19:20         ` Rafael J. Wysocki
2011-08-08  3:48           ` Yanmin Zhang
2011-08-08 20:37             ` Rafael J. Wysocki
2011-08-08 21:01               ` Greg KH
2011-08-08 21:05                 ` Pavel Machek
2011-08-08 21:14                   ` Rafael J. Wysocki
2011-08-08 21:54                     ` Pavel Machek
2011-08-08 22:09                       ` Rafael J. Wysocki
2011-08-10 22:27                         ` Pavel Machek
2011-08-11 19:48                           ` Rafael J. Wysocki
2011-08-04 19:05 ` Len Brown
2011-08-04 19:17   ` Randy Dunlap
2011-08-04 19:50     ` Rafael J. Wysocki

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.