All of lore.kernel.org
 help / color / mirror / Atom feed
From: Riccardo Mancini <rickyman7@gmail.com>
To: Arnaldo Carvalho de Melo <acme@kernel.org>
Cc: Ian Rogers <irogers@google.com>,
	Namhyung Kim <namhyung@kernel.org>,
	Peter Zijlstra <peterz@infradead.org>,
	Ingo Molnar <mingo@redhat.com>,
	Mark Rutland <mark.rutland@arm.com>, Jiri Olsa <jolsa@redhat.com>,
	linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org,
	Alexey Bayduraev <alexey.v.bayduraev@linux.intel.com>,
	Riccardo Mancini <rickyman7@gmail.com>
Subject: [RFC PATCH v3 09/15] perf workqueue: spinup threads when needed
Date: Fri, 20 Aug 2021 12:53:55 +0200	[thread overview]
Message-ID: <c50a4628b86c445391014fb16709c11f72082454.1629454773.git.rickyman7@gmail.com> (raw)
In-Reply-To: <cover.1629454773.git.rickyman7@gmail.com>

This patch adds lazy thread creation in the workqueue.
When a new work is submitted, first an idle worker is searched. If one
is found, it will be selected for execution. Otherwise, a not already
spawned thread is searched. If found, it will be spun up and selected.
If none of the latter is found, one of the busy threads is chosen using
a round-robin policy.

Signed-off-by: Riccardo Mancini <rickyman7@gmail.com>
---
 tools/perf/util/workqueue/workqueue.c | 54 +++++++++++++++++++--------
 1 file changed, 38 insertions(+), 16 deletions(-)

diff --git a/tools/perf/util/workqueue/workqueue.c b/tools/perf/util/workqueue/workqueue.c
index 1092ece9ad39d6d2..305a9cda39810b84 100644
--- a/tools/perf/util/workqueue/workqueue.c
+++ b/tools/perf/util/workqueue/workqueue.c
@@ -39,6 +39,7 @@ struct workqueue_struct {
 	int			msg_pipe[2];	/* main thread comm pipes */
 	struct worker		**workers;	/* array of all workers */
 	struct worker		*next_worker;	/* next worker to choose (round robin) */
+	int			first_stopped_worker; /* next worker to start if needed */
 };
 
 static const char * const workqueue_errno_str[] = {
@@ -423,8 +424,7 @@ static void worker_thread(int tidx, struct task_struct *task)
  */
 struct workqueue_struct *create_workqueue(int nr_threads)
 {
-	int ret, err = 0, t;
-	struct worker *worker;
+	int ret, err = 0;
 	struct workqueue_struct *wq = zalloc(sizeof(struct workqueue_struct));
 
 	if (!wq) {
@@ -474,24 +474,11 @@ struct workqueue_struct *create_workqueue(int nr_threads)
 		goto out_close_pipe;
 	}
 
-	for (t = 0; t < nr_threads; t++) {
-		err = spinup_worker(wq, t);
-		if (err)
-			goto out_stop_pool;
-	}
-
 	wq->next_worker = NULL;
+	wq->first_stopped_worker = 0;
 
 	return wq;
 
-out_stop_pool:
-	lock_workqueue(wq);
-	for_each_idle_worker(wq, worker) {
-		ret = stop_worker(worker);
-		if (ret)
-			err = ret;
-	}
-	unlock_workqueue(wq);
 out_close_pipe:
 	close(wq->msg_pipe[0]);
 	wq->msg_pipe[0] = -1;
@@ -686,10 +673,28 @@ __releases(&worker->lock)
  */
 int queue_work(struct workqueue_struct *wq, struct work_struct *work)
 {
+	int ret;
 	struct worker *worker;
 
+repeat:
 	lock_workqueue(wq);
 	if (list_empty(&wq->idle_list)) {
+		// find a worker to spin up
+		while (wq->first_stopped_worker < threadpool__size(wq->pool)
+				&& wq->workers[wq->first_stopped_worker])
+			wq->first_stopped_worker++;
+
+		// found one
+		if (wq->first_stopped_worker < threadpool__size(wq->pool)) {
+			// spinup does not hold the lock to make the thread register itself
+			unlock_workqueue(wq);
+			ret = spinup_worker(wq, wq->first_stopped_worker);
+			if (ret)
+				return ret;
+			// worker is now in idle_list
+			goto repeat;
+		}
+
 		worker = wq->next_worker;
 		advance_next_worker(wq);
 	} else {
@@ -705,7 +710,24 @@ int queue_work(struct workqueue_struct *wq, struct work_struct *work)
  */
 int queue_work_on_worker(int tidx, struct workqueue_struct *wq, struct work_struct *work)
 {
+	int ret;
+
 	lock_workqueue(wq);
+	if (!wq->workers[tidx]) {
+		// spinup does not hold the lock to make the thread register itself
+		unlock_workqueue(wq);
+		ret = spinup_worker(wq, tidx);
+		if (ret)
+			return ret;
+
+		// now recheck if worker is available
+		lock_workqueue(wq);
+		if (!wq->workers[tidx]) {
+			unlock_workqueue(wq);
+			return -WORKQUEUE_ERROR__NOTREADY;
+		}
+	}
+
 	lock_worker(wq->workers[tidx]);
 	return __queue_work_on_worker(wq, wq->workers[tidx], work);
 }
-- 
2.31.1


  parent reply	other threads:[~2021-08-20 10:54 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-08-20 10:53 [RFC PATCH v3 00/15] perf: add workqueue library and use it in synthetic-events Riccardo Mancini
2021-08-20 10:53 ` [RFC PATCH v3 01/15] perf workqueue: threadpool creation and destruction Riccardo Mancini
2021-08-20 10:53 ` [RFC PATCH v3 02/15] perf tests: add test for workqueue Riccardo Mancini
2021-08-20 10:53 ` [RFC PATCH v3 03/15] perf workqueue: add threadpool start and stop functions Riccardo Mancini
2021-08-20 10:53 ` [RFC PATCH v3 04/15] perf workqueue: add threadpool execute and wait functions Riccardo Mancini
2021-08-20 10:53 ` [RFC PATCH v3 05/15] tools: add sparse context/locking annotations in compiler-types.h Riccardo Mancini
2021-08-20 10:53 ` [RFC PATCH v3 06/15] perf workqueue: introduce workqueue struct Riccardo Mancini
2021-08-24 19:27   ` Namhyung Kim
2021-08-31 16:13     ` Riccardo Mancini
2021-08-20 10:53 ` [RFC PATCH v3 07/15] perf workqueue: implement worker thread and management Riccardo Mancini
2021-08-30  7:22   ` Jiri Olsa
2021-08-20 10:53 ` [RFC PATCH v3 08/15] perf workqueue: add queue_work and flush_workqueue functions Riccardo Mancini
2021-08-24 19:40   ` Namhyung Kim
2021-08-31 16:23     ` Riccardo Mancini
2021-08-20 10:53 ` Riccardo Mancini [this message]
2021-08-20 10:53 ` [RFC PATCH v3 10/15] perf workqueue: create global workqueue Riccardo Mancini
2021-08-20 10:53 ` [RFC PATCH v3 11/15] perf workqueue: add utility to execute a for loop in parallel Riccardo Mancini
2021-08-20 10:53 ` [RFC PATCH v3 12/15] perf record: setup global workqueue Riccardo Mancini
2021-08-20 10:53 ` [RFC PATCH v3 13/15] perf top: " Riccardo Mancini
2021-08-20 10:54 ` [RFC PATCH v3 14/15] perf test/synthesis: " Riccardo Mancini
2021-08-20 10:54 ` [RFC PATCH v3 15/15] perf synthetic-events: use workqueue parallel_for Riccardo Mancini
2021-08-29 21:59 ` [RFC PATCH v3 00/15] perf: add workqueue library and use it in synthetic-events Jiri Olsa
2021-08-31 15:46   ` Jiri Olsa
2021-08-31 16:57     ` Riccardo Mancini

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=c50a4628b86c445391014fb16709c11f72082454.1629454773.git.rickyman7@gmail.com \
    --to=rickyman7@gmail.com \
    --cc=acme@kernel.org \
    --cc=alexey.v.bayduraev@linux.intel.com \
    --cc=irogers@google.com \
    --cc=jolsa@redhat.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-perf-users@vger.kernel.org \
    --cc=mark.rutland@arm.com \
    --cc=mingo@redhat.com \
    --cc=namhyung@kernel.org \
    --cc=peterz@infradead.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 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.