public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
From: Frederic Weisbecker <fweisbec@gmail.com>
To: Arjan van de Ven <arjan@infradead.org>
Cc: Cornelia Huck <cornelia.huck@de.ibm.com>,
	lkml <linux-kernel@vger.kernel.org>
Subject: [PATCH] fastboot: keep at least one thread per cpu during boot
Date: Mon, 9 Feb 2009 04:48:27 +0100	[thread overview]
Message-ID: <20090209034826.GA4768@nowhere> (raw)

Async threads are created and destroyed depending on the number of jobs in queue.
It means that several async threads can be created for a specific batch of work,
then the threads will die after the completion of this batch, but they could be
needed just after this completion for another batch of work.
During the boot, such repetitive thread creations can be wasteful, that's why
this patch proposes to keep at least one thread per cpu (if they already have
been created once). Such a threshold of threads kept alive will prevent from
a part of the thread creation overhead.
This threshold will be dropped one the system_state switches from SYSTEM_BOOTING
to SYSTEM_RUNNING.

Note:
_ If this patch is accepted, I will try to extend it to modules loading on boot
_ One thread per cpu could sound a bit arbitrary here. Actually this is compromize
between memory saving (if we just created lots of async thread for a large batch
of jobs) and task creation overhead.

Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
---
 include/linux/async.h |    2 +
 init/main.c           |    1 +
 kernel/async.c        |   52 +++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 53 insertions(+), 2 deletions(-)

diff --git a/include/linux/async.h b/include/linux/async.h
index 68a9530..71a09e2 100644
--- a/include/linux/async.h
+++ b/include/linux/async.h
@@ -25,3 +25,5 @@ extern void async_synchronize_cookie(async_cookie_t cookie);
 extern void async_synchronize_cookie_domain(async_cookie_t cookie,
 					    struct list_head *list);
 
+extern void async_finish_boot(void);
+
diff --git a/init/main.c b/init/main.c
index 36de89b..fa99928 100644
--- a/init/main.c
+++ b/init/main.c
@@ -806,6 +806,7 @@ static noinline int init_post(void)
 	unlock_kernel();
 	mark_rodata_ro();
 	system_state = SYSTEM_RUNNING;
+	async_finish_boot();
 	numa_default_policy();
 
 	if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
diff --git a/kernel/async.c b/kernel/async.c
index f565891..25c12d0 100644
--- a/kernel/async.c
+++ b/kernel/async.c
@@ -176,7 +176,7 @@ static async_cookie_t __async_schedule(async_func_ptr *ptr, void *data, struct l
 	struct async_entry *entry;
 	unsigned long flags;
 	async_cookie_t newcookie;
-	
+
 
 	/* allow irq-off callers */
 	entry = kzalloc(sizeof(struct async_entry), GFP_ATOMIC);
@@ -313,6 +313,54 @@ void async_synchronize_cookie(async_cookie_t cookie)
 EXPORT_SYMBOL_GPL(async_synchronize_cookie);
 
 
+/**
+ * async_finish_boot - wake up the async thread which stayed alive only to keep
+ * the minimum threshold of async threads on boot.
+ */
+void async_finish_boot(void)
+{
+	wake_up(&async_new);
+}
+
+/**
+ * Adaptive wait function for the async threads.
+ * While booting, we want to keep about one thread per
+ * cpu to avoid wasteful threads creations/deletions.
+ * We return in the normal async thread creation/deletion mode once
+ * the boot is finished, since async is most used during the boot.
+ *
+ * @return: 0 if we assume the thread should be destroyed
+ */
+static int async_thread_sleep(int timeout)
+{
+	static atomic_t nb_sleeping = ATOMIC_INIT(-1);
+	int tc;
+	int ret;
+
+	/*
+	 * If several async threads come here together and if we are in the
+	 * boot stage, those which overlap the number of boot thread threshold
+	 * will sleep and then assume they have to die...
+	 */
+	tc = atomic_read(&thread_count) - atomic_inc_return(&nb_sleeping);
+
+	if (system_state == SYSTEM_BOOTING && tc <= num_online_cpus()) {
+		schedule();
+		if (system_state == SYSTEM_RUNNING)
+			/* We may have been awoken by async_finish_boot() */
+			ret = 0;
+		else
+			/* We may have a job to handle */
+			ret = timeout;
+	} else {
+		ret = schedule_timeout(timeout);
+	}
+
+	atomic_dec(&nb_sleeping);
+
+	return ret;
+}
+
 static int async_thread(void *unused)
 {
 	DECLARE_WAITQUEUE(wq, current);
@@ -330,7 +378,7 @@ static int async_thread(void *unused)
 		if (!list_empty(&async_pending))
 			run_one_entry();
 		else
-			ret = schedule_timeout(HZ);
+			ret = async_thread_sleep(ret);
 
 		if (ret == 0) {
 			/*


             reply	other threads:[~2009-02-09  3:48 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-02-09  3:48 Frederic Weisbecker [this message]
2009-02-09  5:27 ` [PATCH] fastboot: keep at least one thread per cpu during boot Arjan van de Ven
2009-02-09 10:17   ` Cornelia Huck
2009-02-09 13:34   ` Frederic Weisbecker

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090209034826.GA4768@nowhere \
    --to=fweisbec@gmail.com \
    --cc=arjan@infradead.org \
    --cc=cornelia.huck@de.ibm.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox