Received: by 2002:a05:6a10:f3d0:0:0:0:0 with SMTP id a16csp3842286pxv; Tue, 13 Jul 2021 05:13:06 -0700 (PDT) X-Google-Smtp-Source: ABdhPJw/C8XL9Jg4iUnDgleTjiXCes//M+5UBN3TkZheYUHY7Ya5mJgyA7feeci0lVWkmGVJ/UX5 X-Received: by 2002:a05:6402:1849:: with SMTP id v9mr5205423edy.108.1626178386004; Tue, 13 Jul 2021 05:13:06 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1626178385; cv=none; d=google.com; s=arc-20160816; b=qD3S/h3hqiLmgQ3WpMeFi36vBuA6nRh3smlyIEgljeGZWzVejTXrKY2YWsn0fz2KGC FcB90W5xcnQbvI7Tphw57+SBuifjS0VN3/yuTCjvRNA8AYt7o8G+R0faMm4EU8FtE9fW hBWfMXBuYYk4m8kGwTIrq5Jn3RVbWYy+9b0T1xwtwqVuSHW5ffShVAslu17culbx7d24 zL+UaKjZMyFNedbxHSL2+L0jILx9cH8yhVuD5+s/Qv93dPhjCCdh8vwgh5CW6HY399Vn gnv+3V5CyZ036n7Ypmuoas7vdkjISE/OKnQSYPHF0dO2U5o9eoFNSUb5S9P8C4PJOShu w7Ag== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :references:in-reply-to:message-id:date:subject:cc:to:from :dkim-signature; bh=Zbu3xed4FVceBb1sRv3k/hOdnw405/iMg8ZcmcQ4j3c=; b=Y4J9ANU41WRftkqimuFVZCjiJeQx9P3IPj8ZyUh8H4Xj0J2eKWgfpCiGw/HWhDaa0y 9MIsroDJfoT3qXAi9m8ZrRKTMwogzRP3Jph06FbbUrpcjCzSiQP8AZuTlLYyrvRgEWem ccncin1cl4m8Z3FnkdIGsm764hdM+OI041lSPEYnzI8J2XlW98T2YZH23AfpzfbfnAqj SjQyVlm/xb4i9CSaCnQ2DkJj+5B9uYSWmu2vRAF8JwsbYkfRSljP1k5XMw5xYsnC5W8R lcyJU0z/ZrzPEqY3FklEu9Ctm+U1ibTq00rrpStQkNYndIpCFyEsIBuvwOBMsMMswlwT G11g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=hwMbFft4; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id m25si20678405ejb.570.2021.07.13.05.12.43; Tue, 13 Jul 2021 05:13:05 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20161025 header.b=hwMbFft4; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235972AbhGMMOZ (ORCPT + 99 others); Tue, 13 Jul 2021 08:14:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40866 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235797AbhGMMOY (ORCPT ); Tue, 13 Jul 2021 08:14:24 -0400 Received: from mail-wr1-x42b.google.com (mail-wr1-x42b.google.com [IPv6:2a00:1450:4864:20::42b]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id ED564C0613E9; Tue, 13 Jul 2021 05:11:33 -0700 (PDT) Received: by mail-wr1-x42b.google.com with SMTP id f17so30177405wrt.6; Tue, 13 Jul 2021 05:11:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=Zbu3xed4FVceBb1sRv3k/hOdnw405/iMg8ZcmcQ4j3c=; b=hwMbFft4JUQI4rQNZtIBq9c7gFRSEoJFX4b4v4Wi6StcvjeA634ybZno9+Uv+IEWbc s29m+uHuM7eLe/80WwEvFSTS13ID4rScEgsk/l8EgQCp4hIGqijKdKQrw0kyO11xQRap 3G07HS/eVX07V6J+5pGyP8sv8onpb5M6STAAB60sq6DPkReFspyKZxa0oBSX1W7/gHPQ oqW4l8A2cZHh3YNx2fdXwrRaRhN/NynXIvUPWR8KNUAPapw8DsGM52kJkFLboOUj3EXJ KtRmOUz3Pq7ImDDC3czmqxH0TxymQC/K530O8oJ4hxZBUo1vyO7ve1s82NxTY5sfZLkP 4mfQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=Zbu3xed4FVceBb1sRv3k/hOdnw405/iMg8ZcmcQ4j3c=; b=mLRd5ztX6bLtZ5/sik3VzoOed1bKNYmK3B6n+VZeRJ002c9/21XtsEOmqmhXMjjoXQ F3QGnglsKVab7GtWcYqqFybvw8JdHxPC3drMe9QwffsVdURp7p5XaSrFH0mVllMHLL0e SBEm47EDzDUAUE4O/WBssoCVyBgJWUfRftYKbdWUg4cdH6XvFdQpZwxmA1XTAekjcUJt /OVqAVhu8I4wPWGVQ61QLOZjKiNUZVZJW1qhoBNzCpHC2jomieq02Xvx6k4LoCbdvaby cb7+2eosLoMRRKf4by0Nt2wXYphsSBM/LkhRplZg8QrVq4tdhvI48QN5qEMmJjhmxVmo g9dQ== X-Gm-Message-State: AOAM5306attXjntj85sORi2nb7KMKSJ0iisGXZV6szpNHtUqBaKO7EvJ Bq6ZYWccsDMPR+HBUFOWT1o= X-Received: by 2002:a05:6000:1d1:: with SMTP id t17mr5155623wrx.267.1626178292398; Tue, 13 Jul 2021 05:11:32 -0700 (PDT) Received: from localhost.localdomain ([2001:b07:6456:fd99:ced0:db1c:53e1:191e]) by smtp.googlemail.com with ESMTPSA id o3sm17551425wrw.56.2021.07.13.05.11.31 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 13 Jul 2021 05:11:31 -0700 (PDT) From: Riccardo Mancini To: Arnaldo Carvalho de Melo Cc: Ian Rogers , Namhyung Kim , Peter Zijlstra , Ingo Molnar , Mark Rutland , Jiri Olsa , linux-kernel@vger.kernel.org, linux-perf-users@vger.kernel.org, Riccardo Mancini , Alexey Bayduraev Subject: [RFC PATCH 01/10] perf workqueue: threadpool creation and destruction Date: Tue, 13 Jul 2021 14:11:12 +0200 Message-Id: <46f9e291af3d87c212d279717d56eeab4cbfde68.1626177381.git.rickyman7@gmail.com> X-Mailer: git-send-email 2.31.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The workqueue library is made up by two components: - threadpool: handles the lifetime of the threads - workqueue: handles work distribution among the threads This first patch introduces the threadpool, starting from its creation and destruction functions. Thread management is based on the prototype from Alexey: https://lore.kernel.org/lkml/cover.1625227739.git.alexey.v.bayduraev@linux.intel.com/ Each thread in the threadpool executes the same function (aka task) with a different argument tidx. Threads use a pair of pipes to communicate with the main process. The threadpool is static (all threads will be spawned at the same time). Future work could include making it resizable and adding affinity support (as in Alexey prototype). Suggested-by: Alexey Bayduraev Signed-off-by: Riccardo Mancini --- tools/perf/util/Build | 1 + tools/perf/util/workqueue/Build | 1 + tools/perf/util/workqueue/threadpool.c | 175 +++++++++++++++++++++++++ tools/perf/util/workqueue/threadpool.h | 19 +++ 4 files changed, 196 insertions(+) create mode 100644 tools/perf/util/workqueue/Build create mode 100644 tools/perf/util/workqueue/threadpool.c create mode 100644 tools/perf/util/workqueue/threadpool.h diff --git a/tools/perf/util/Build b/tools/perf/util/Build index 2d4fa13041789cd6..c7b09701661c869d 100644 --- a/tools/perf/util/Build +++ b/tools/perf/util/Build @@ -180,6 +180,7 @@ perf-$(CONFIG_LIBBABELTRACE) += data-convert-bt.o perf-y += data-convert-json.o perf-y += scripting-engines/ +perf-y += workqueue/ perf-$(CONFIG_ZLIB) += zlib.o perf-$(CONFIG_LZMA) += lzma.o diff --git a/tools/perf/util/workqueue/Build b/tools/perf/util/workqueue/Build new file mode 100644 index 0000000000000000..8b72a6cd4e2cba0d --- /dev/null +++ b/tools/perf/util/workqueue/Build @@ -0,0 +1 @@ +perf-y += threadpool.o diff --git a/tools/perf/util/workqueue/threadpool.c b/tools/perf/util/workqueue/threadpool.c new file mode 100644 index 0000000000000000..70c67569f956a3e2 --- /dev/null +++ b/tools/perf/util/workqueue/threadpool.c @@ -0,0 +1,175 @@ +// SPDX-License-Identifier: GPL-2.0 +#include +#include +#include +#include +#include +#include "debug.h" +#include "asm/bug.h" +#include "threadpool.h" + +enum threadpool_status { + THREADPOOL_STATUS__STOPPED, /* no threads */ + THREADPOOL_STATUS__ERROR, /* errors */ + THREADPOOL_STATUS__MAX +}; + +struct threadpool_struct { + int nr_threads; /* number of threads in the pool */ + struct thread_struct *threads; /* array of threads in the pool */ + struct task_struct *current_task; /* current executing function */ + enum threadpool_status status; /* current status of the pool */ +}; + +struct thread_struct { + int idx; /* idx of thread in pool->threads */ + pid_t tid; /* tid of thread */ + struct threadpool_struct *pool; /* parent threadpool */ + struct { + int from[2]; /* messages from thread (acks) */ + int to[2]; /* messages to thread (commands) */ + } pipes; +}; + +/** + * init_pipes - initialize all pipes of @thread + */ +static void init_pipes(struct thread_struct *thread) +{ + thread->pipes.from[0] = -1; + thread->pipes.from[1] = -1; + thread->pipes.to[0] = -1; + thread->pipes.to[1] = -1; +} + +/** + * open_pipes - open all pipes of @thread + */ +static int open_pipes(struct thread_struct *thread) +{ + if (pipe(thread->pipes.from)) { + pr_err("threadpool: failed to create comm pipe 'from': %s\n", + strerror(errno)); + return -ENOMEM; + } + + if (pipe(thread->pipes.to)) { + pr_err("threadpool: failed to create comm pipe 'to': %s\n", + strerror(errno)); + close(thread->pipes.from[0]); + thread->pipes.from[0] = -1; + close(thread->pipes.from[1]); + thread->pipes.from[1] = -1; + return -ENOMEM; + } + + return 0; +} + +/** + * close_pipes - close all communication pipes of @thread + */ +static void close_pipes(struct thread_struct *thread) +{ + if (thread->pipes.from[0] != -1) { + close(thread->pipes.from[0]); + thread->pipes.from[0] = -1; + } + if (thread->pipes.from[1] != -1) { + close(thread->pipes.from[1]); + thread->pipes.from[1] = -1; + } + if (thread->pipes.to[0] != -1) { + close(thread->pipes.to[0]); + thread->pipes.to[0] = -1; + } + if (thread->pipes.to[1] != -1) { + close(thread->pipes.to[1]); + thread->pipes.to[1] = -1; + } +} + +/** + * create_threadpool - create a fixed threadpool with @n_threads threads + */ +struct threadpool_struct *create_threadpool(int n_threads) +{ + int ret, t; + struct threadpool_struct *pool = malloc(sizeof(*pool)); + + if (!pool) { + pr_err("threadpool: cannot allocate pool: %s\n", + strerror(errno)); + return NULL; + } + + if (n_threads <= 0) { + pr_err("threadpool: invalid number of threads: %d\n", + n_threads); + goto out_free_pool; + } + + pool->nr_threads = n_threads; + pool->current_task = NULL; + + pool->threads = malloc(n_threads * sizeof(*pool->threads)); + if (!pool->threads) { + pr_err("threadpool: cannot allocate threads: %s\n", + strerror(errno)); + goto out_free_pool; + } + + for (t = 0; t < n_threads; t++) { + pool->threads[t].idx = t; + pool->threads[t].tid = -1; + pool->threads[t].pool = pool; + init_pipes(&pool->threads[t]); + } + + for (t = 0; t < n_threads; t++) { + ret = open_pipes(&pool->threads[t]); + if (ret) + goto out_close_pipes; + } + + pool->status = THREADPOOL_STATUS__STOPPED; + + return pool; + +out_close_pipes: + for (t = 0; t < n_threads; t++) + close_pipes(&pool->threads[t]); + + free(pool->threads); +out_free_pool: + free(pool); + return NULL; +} + +/** + * destroy_threadpool - free the @pool and all its resources + */ +void destroy_threadpool(struct threadpool_struct *pool) +{ + int t; + + if (!pool) + return; + + WARN_ON(pool->status != THREADPOOL_STATUS__STOPPED + && pool->status != THREADPOOL_STATUS__ERROR); + + for (t = 0; t < pool->nr_threads; t++) + close_pipes(&pool->threads[t]); + + free(pool->threads); + free(pool); +} + +/** + * threadpool_size - get number of threads in the threadpool + */ +int threadpool_size(struct threadpool_struct *pool) +{ + return pool->nr_threads; +} diff --git a/tools/perf/util/workqueue/threadpool.h b/tools/perf/util/workqueue/threadpool.h new file mode 100644 index 0000000000000000..2b9388c768a0b588 --- /dev/null +++ b/tools/perf/util/workqueue/threadpool.h @@ -0,0 +1,19 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef __WORKQUEUE_THREADPOOL_H +#define __WORKQUEUE_THREADPOOL_H + +struct threadpool_struct; +struct task_struct; + +typedef void (*task_func_t)(int tidx, struct task_struct *task); + +struct task_struct { + task_func_t fn; +}; + +extern struct threadpool_struct *create_threadpool(int n_threads); +extern void destroy_threadpool(struct threadpool_struct *pool); + +extern int threadpool_size(struct threadpool_struct *pool); + +#endif /* __WORKQUEUE_THREADPOOL_H */ -- 2.31.1