From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755487AbbEZOF7 (ORCPT ); Tue, 26 May 2015 10:05:59 -0400 Received: from mailout2.samsung.com ([203.254.224.25]:63508 "EHLO mailout2.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754106AbbEZOFv (ORCPT ); Tue, 26 May 2015 10:05:51 -0400 X-AuditID: cbfee68e-f79c56d000006efb-f0-55647dbdaf15 Date: Tue, 26 May 2015 14:05:49 +0000 (GMT) From: =?euc-kr?B?wMzAusXD?= Subject: [RFC PATCH] suspend/resume performance improvement To: rjw@rjwysocki.net, pavel@ucw.cz, len.brown@intel.com, linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org Reply-to: eun.taik.lee@samsung.com MIME-version: 1.0 X-MTR: 20150526114245687@eun.taik.lee Msgkey: 20150526114245687@eun.taik.lee X-EPLocale: ko_KR.euc-kr X-Priority: 3 X-EPWebmail-Msg-Type: personal X-EPWebmail-Reply-Demand: 0 X-EPApproval-Locale: X-EPHeader: ML X-MLAttribute: X-RootMTR: 20150526114245687@eun.taik.lee X-ParentMTR: X-ArchiveUser: EV X-CPGSPASS: N X-ConfirmMail: N,general Content-type: text/plain; charset=euc-kr MIME-version: 1.0 Message-id: <1141174354.499851432649147087.JavaMail.weblogic@epmlwas01d> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprLJsWRmVeSWpSXmKPExsVy+t8zXd29tSmhBo/nC1hc3jWHzYHR4/Mm uQDGqAZGm8Si5IzMslSF1Lzk/JTMvHRbpdAQN10LJYWM/OISW6VoIwNjPSNTEz0jE3M9S4NY KyNTJYW8xNxUW6UKXaheJYWi5AKg2tzKYqABOal6UHG94tS8FIes/FKQS/SKE3OLS/PS9ZLz c5UUyhJzSoFGKOknTGXMmPariblgm2XFjsnTmRsYv5h3MXJyCAmoS5zYvYYFxJYQMJHYePk5 K4QtJnHh3nq2LkYuoJpljBKvHj5ihCla9uUmC0RiDqPEqV27mEESLAKqEtt2LwArYhMwl2iZ upgJxBYWsJY4/vgwO0iDiMBERommpu1sEKuVJOYfbgBbzSsgKHFy5hOoM1Ql1jzdyQwRV5P4 vfYRO0RcQmLW9AtQ5/FKzGh/ClUvJzHt6xpmCFta4vysDYwwLyz+/hgqzi9x7PYOJghbQGLq mYNQNVoSF56fhZrDJ7Fm4VsoW1Di9LVuZphd97fMZYK5YWvLE7AbmAUUJaZ0P2SHsLUkvvzY x4buF14BD4kJkxeDg1FCoJND4siNq0yQ0BKQ+Db5EMsERsVZSHpmIZk7C8lcZDULGFlWMYqm FiQXFCelFxkhR/gmRkg67NvBePOA9SFGAQ5GJR5ei8PJoUKsiWXFlbmHGJOBVk9klhJNzgcm 3bySeENjMyMLUxNTYyNzSzMMYRNTCwsTIxzCSuK8CVI/g4UE0hNLUrNTUwtSi+KLSnNSiw8x MnFwSjUw9u/qEdnG4jnnyZ3+Ke/2v8nacrVEPWh5X9LCcz5cj15HTjgZWf87Qabu9bEF85jl 2F70qRzYfCazPSyp+8W2pJ96Qa3Vz6Jn/lgQ+DKw/Enepoh94lqTmndwRbeH8yQ4N3HJ+BTs +7vmcgcrj3CnaN6Bh5dfBKUwTu1+o22t8vyQPF+o6TdjJZbijERDLeai4kQAgBAThbADAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFtrHKsWRmVeSWpSXmKPExsVy+t/tXt29tSmhBjvv8Fhc3jWHzYHR4/Mm uQDGqAybjNTElNQihdS85PyUzLx0WyXv4HjneFMzA0NdQ0sLcyWFvMTcVFslF58AXbfMHKCh SgpliTmlQKGAxOJiJX07m6L80pJUhYz84hJbpWgjA2M9I1MTPSNjAz0Tg1grQwMDI1OgqoSM jGm/mpgLtllW7Jg8nbmB8Yt5FyMnh5CAusSJ3WtYQGwJAROJZV9uQtliEhfurWfrYuQCqpnD KHFq1y5mkASLgKrEtt0LGEFsNgFziZapi5lAbGEBa4njjw+zgzSICExklGhq2s4GsUFJYv7h BrCpvAKCEidnPoHaoCqx5ulOZoi4msTvtY/YIeISErOmX2CFsHklZrQ/haqXk5j2dQ0zhC0t cX7WBkaYSxd/fwwV55c4dnsHE4QtIDH1zEGoGi2JC8/PQs3hk1iz8C2ULShx+lo3M8yu+1vm MsHcsLXlCdgNzAKKElO6H7JD2FoSX37sY0P3C6+Ah8SEyYvZJjDKzEKSmoWkfRaSdmQ1CxhZ VjGKphYkFxQnpVcY6RUn5haX5qXrJefnbmIEp51ni3Yw/jtvfYhRgINRiYfX4nByqBBrYllx Ze4hRgkOZiUR3sXVKaFCvCmJlVWpRfnxRaU5qcWHGE2BUTWRWUo0OR+YEvNK4g2NDYwNDS3N DUwNjSyUxHn/n8sNERJITyxJzU5NLUgtgulj4uCUamBcaVdw+IzM/Mvv466uEdj7Js//wJuf O+ZIL3cU5jVoTQ157zpn32Tj0Hcs8mssevp+LHvxe/mmTZmF4bIlsROkJ3U15N3drbdkwjef OQk28QcjVNmsrt1dv8Dd+Gj434W6r9bZyJ9XFHvw+69ZwZ+QbEmndNEugbLLl6o+3qwX+n6s p/TjmxxnJZbijERDLeai4kQAsyh3bVEDAAA= DLP-Filter: Pass X-CFilter-Loop: Reflected Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Transfer-Encoding: 8bit X-MIME-Autoconverted: from base64 to 8bit by nfs id t4QE69Gk011859 When a task that calls state_store() to suspend the device has used up most of its time slice, suspend sometimes take too long. (User noticeable) Suspend/resume is a system wide operation. So, instead of depending on a userspace task's time slice, let kworker do the work to avoid a long wait on the runqueue. Signed-off-by: Eun Taik Lee --- kernel/power/Kconfig | 12 +++++ kernel/power/main.c | 121 ++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 132 insertions(+), 1 deletion(-) diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig index 7e01f78..7eef317 100644 --- a/kernel/power/Kconfig +++ b/kernel/power/Kconfig @@ -18,6 +18,18 @@ config SUSPEND_FREEZER Turning OFF this setting is NOT recommended! If in doubt, say Y. +config SUSPEND_HELPER + bool "Use kworker for suspend/resume" + depends on SUSPEND + default n + help + Use kworker for suspend/resume functionality to decrease + the suspend/resume time when the caller has used up too much + of its time slice before calling. + Use kworker for suspend/resume functionality to decrease + the suspend/resume time when the caller has used up too much + of its time slice before calling. + config HIBERNATE_CALLBACKS bool diff --git a/kernel/power/main.c b/kernel/power/main.c index 86e8157..e782b86 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c @@ -15,7 +15,7 @@ #include #include #include - +#include #include "power.h" DEFINE_MUTEX(pm_mutex); @@ -335,9 +335,33 @@ static suspend_state_t decode_state(const char *buf, size_t n) return PM_SUSPEND_ON; } +#ifdef CONFIG_SUSPEND_HELPER +static struct workqueue_struct *suspend_helper_wq; +struct state_store_params { + const char *buf; + size_t n; +}; + +struct suspend_helper_data { + struct work_struct work; + struct completion done; + struct state_store_params params; + int result; +}; +struct suspend_helper_data suspend_helper_data; + +static ssize_t state_store_helper(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n); +#endif + static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, const char *buf, size_t n) { +#ifdef CONFIG_SUSPEND_HELPER + pr_debug("%s: Let our helper do the real work!\n", __func__); + return state_store_helper(kobj, attr, buf, n); +#else suspend_state_t state; int error; @@ -361,10 +385,102 @@ static ssize_t state_store(struct kobject *kobj, struct kobj_attribute *attr, out: pm_autosleep_unlock(); return error ? error : n; +#endif } power_attr(state); +#ifdef CONFIG_SUSPEND_HELPER +static void suspend_helper(struct work_struct *work) +{ + struct suspend_helper_data *data = (struct suspend_helper_data *) + container_of(work, struct suspend_helper_data, work); + const char *buf = data->params.buf; + size_t n = data->params.n; + suspend_state_t state; + int error = 0; + + pr_debug("%s: start!\n", __func__); + + error = pm_autosleep_lock(); + if (error) + goto out_nolock; + + if (pm_autosleep_state() > PM_SUSPEND_ON) { + error = -EBUSY; + goto out; + } + + state = decode_state(buf, n); + if (state < PM_SUSPEND_MAX) + error = pm_suspend(state); + else if (state == PM_SUSPEND_MAX) + error = hibernate(); + else + error = -EINVAL; + +out: + pm_autosleep_unlock(); + +out_nolock: + /* set result and notify completion */ + data->result = error; + complete(&data->done); + + pr_debug("%s: result = %d\n", __func__, error); +} + +static ssize_t state_store_helper(struct kobject *kobj, + struct kobj_attribute *attr, + const char *buf, size_t n) +{ + int error; + int freezable = 0; + + /* we don't need to freeze. so tell the freezer */ + if (!freezer_should_skip(current)) { + freezable = 1; + freezer_do_not_count(); + pr_debug("%s: freezer should skip me (%s:%d)\n", + __func__, current->comm, current->pid); + } + + suspend_helper_data.params.buf = buf; + suspend_helper_data.params.n = n; + init_completion(&suspend_helper_data.done); + + /* use kworker for suspend resume */ + queue_work(suspend_helper_wq, &suspend_helper_data.work); + + /* wait for suspend/resume work to be complete */ + wait_for_completion(&suspend_helper_data.done); + + if (freezable) { + /* set ourself as freezable */ + freezer_count(); + } + + error = suspend_helper_data.result; + pr_debug("%s: suspend_helper returned %d\n", __func__, error); + + return error ? error : n; +} + +static int suspend_helper_init(void) +{ + suspend_helper_wq = alloc_ordered_workqueue("suspend_helper", 0); + if (!suspend_helper_wq) + return -ENOMEM; + + INIT_WORK(&suspend_helper_data.work, suspend_helper); + init_completion(&suspend_helper_data.done); + + pr_debug("%s: init done\n", __func__); + + return 0; +} +#endif /* CONFIG_SUSPEND_HELPER */ + #ifdef CONFIG_PM_SLEEP /* * The 'wakeup_count' attribute, along with the functions defined in @@ -640,6 +756,9 @@ static int __init pm_init(void) if (error) return error; pm_print_times_init(); +#ifdef CONFIG_SUSPEND_HELPER + suspend_helper_init(); +#endif return pm_autosleep_init(); } -- 1.9.1 {.n++%ݶw{.n+{G{ayʇڙ,jfhz_(階ݢj"mG?&~iOzv^m ?I