From patchwork Tue Aug 29 12:59:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nuo Mi X-Patchwork-Id: 43393 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:3822:b0:149:dfde:5c0a with SMTP id p34csp793623pzf; Tue, 29 Aug 2023 06:06:10 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGrXyNFckVk9kUW8Gl5o65GpqDmeVzI28/S9ES63JAJDfU+5CZIRlOFpXAQYfQp6H27Ad9H X-Received: by 2002:a05:6402:3493:b0:522:ab20:368a with SMTP id v19-20020a056402349300b00522ab20368amr2823105edc.13.1693314369811; Tue, 29 Aug 2023 06:06:09 -0700 (PDT) Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id bc13-20020a056402204d00b0052567bef5d2si5868595edb.43.2023.08.29.06.05.44; Tue, 29 Aug 2023 06:06:09 -0700 (PDT) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; dkim=neutral (body hash did not verify) header.i=@outlook.com header.s=selector1 header.b=CKJDkSpo; arc=fail (body hash mismatch); spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id D988768C6B3; Tue, 29 Aug 2023 16:05:40 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from APC01-PSA-obe.outbound.protection.outlook.com (mail-psaapc01olkn2092.outbound.protection.outlook.com [40.92.52.92]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id F32E768C602 for ; Tue, 29 Aug 2023 16:05:33 +0300 (EEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=KcgG8p+DWqKHZXwoeqBeHfXaerB2KSI1w/pbAL+Gsk3HoDXfFS3bYLL13I7+weR1z67h4IRzRZxRlFSGVT41KJaYPYQriIi9CUPX/p3kPvbMyqTZ03kGqtmhGZwQLclsFin9YoiwdzVWJtu/FOyCfCCa4f8g2ISs5vAqLuARoN1Z2OWvMxsBkUHhTOcZXG4OVDrHiZwFAdXuYtya1Ji/5We9o7Li5Q73O2BeFUkYvTqO+TH1Vjcmz1fTMiIXJSdeS7i9hTzMt1wz2sPA/g4ASC304K5V17iTABB/Htdpdr6rYPfOqmSc0zURc5lSWsQ/gVexPVHS3HUdJIufc9PaKQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=JKWaWQ3IP5+CQXqv8V5C+RNJdClRue+QrRAHNKh/cYc=; b=jD+FAdbXV4u3Fa/vmlvj3VETpX7qhonVuv6OvayXnZZjwEJsgCC2JGvj5/47BKYBftF86shrd5ruEfZ5BpahxEaC5KHMMqpGRboFuRf17tVjd6aW2uRtb0h8tJ1BiLpr6IW7TDd7iP12E27KA3rXZCCYFhrt3qEwgHcvDup9mtsTgS/F0tgly0FH54I2w2ITIWj05kMY99WQ5LHrFJcVypYU+MbRwBaLnb0/bJwEHdPGmq4dN7jFOyJevjhIK9hMG3sAi/on5DMFu8t/yg+iQoDACjsTSu88n/hOw/3NofNPO0eMUvilcUN8bIpa7Vf6ixlSYoAOpd9/KFcJsWHA9g== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=outlook.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=JKWaWQ3IP5+CQXqv8V5C+RNJdClRue+QrRAHNKh/cYc=; b=CKJDkSpoEdwrR7HGa3YOwQMptk6EguP0cOHcrKvZx+YYxr+nxO+7QsyYTYA71d5Xkg9LenLrrJdE1iDoJFbo/FAwRyVjVGsBRYfNiSj26bgJMUJJ0Uq4DL2Ujc47hQdfeqMZYqeoqT7e7TnUv/sCtXECWosvInqcwmFSKu08HxVoMyLe0irhwui+xxTjYXRE6AmhHxxt6Jwxgen8911tFv1PArTmgQpdD0A3+Nv5rDirQ0hs3fG1IFNRg0NlSchWTknji5Q2ZZkT/lH3//R8YoLQafu26nBSO9GcNgTGKjuq/IymjLNl6mxPBa3EuctGZI3Hb8bXyRguJb6rv/Dyyw== Received: from TYSPR06MB6433.apcprd06.prod.outlook.com (2603:1096:400:47a::6) by PSAPR06MB4406.apcprd06.prod.outlook.com (2603:1096:301:80::13) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6699.34; Tue, 29 Aug 2023 13:05:28 +0000 Received: from TYSPR06MB6433.apcprd06.prod.outlook.com ([fe80::f1a4:bbff:7592:ee31]) by TYSPR06MB6433.apcprd06.prod.outlook.com ([fe80::f1a4:bbff:7592:ee31%5]) with mapi id 15.20.6699.034; Tue, 29 Aug 2023 13:05:28 +0000 From: Nuo Mi To: ffmpeg-devel@ffmpeg.org Date: Tue, 29 Aug 2023 20:59:03 +0800 Message-ID: X-Mailer: git-send-email 2.25.1 In-Reply-To: References: X-TMN: [ZZx6PCisBzvcQgdXSdR3Aj5PPSsZ0Xhm] X-ClientProxiedBy: TYCP301CA0016.JPNP301.PROD.OUTLOOK.COM (2603:1096:400:381::17) To TYSPR06MB6433.apcprd06.prod.outlook.com (2603:1096:400:47a::6) X-Microsoft-Original-Message-ID: <20230829125903.9561-1-nuomi2021@gmail.com> MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 2 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: TYSPR06MB6433:EE_|PSAPR06MB4406:EE_ X-MS-Office365-Filtering-Correlation-Id: cd9f8288-3320-4835-0893-08dba8909db8 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: j/RAX5nr2K2100vDK/q/mmwJaOfzLLyaPA/Oprul3HOXf+BaN57LcYMA4ciSqo7FV1xc05PG3uz+X90V3SXUOnvmuQ5wRymqw5mecsC/cSsSpp0WkXhuRpqc4k1vqOMeMng1ZgCd+fjcj/XtnLSWQLQNJ72wUqR6V2q+lVZuY7j0/eOnpezP6FKEY+FZumkj5o8twt0v3gyuEHv58KOe3/qQtebL9r0x5ChBya7k2U2I0Y+2ZJ+e+wb/vv4CeK4IeVIBaO7g37E/Cj55n54X1JGVBbEcy9lhwnsBPg/d3QGo+yHg46zPvLVLFx2bM6ExiICiA7GFUAoHneeEq/RHWT4PK3v2nfTl5+108Hhap3iAsKDVaCXOxXvw8IgC7qxD7dsJTWPIgS+QF//Sczn7pyY4sb4Fj0V3vMm28b7zVl/9ho3unURgPJVZ2VPE5IB2DcmtMdo9UA4d+t6Ros1mb0ChSF/ahELNKH6JA+SnvQm9KCWq0L9nmqN32qgDxos89YihAEkK6wWbIoeaI0D/gPeDgf863TvJzI/wCVkdMHVplwfH6W90jyFhZaLqOaoWmcl4ltZKrEvJ4CarNFmqEv1ekmq8z6HU/hUf2sQbnk8sdW7UKRJ9sN6x3vbV2O1uxNEIwOnIthtJu3LfO2WNpA== X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: F3d4mGhgxvUfJdlWIm0ySeOI4HIHnV3R30wBrtxqC9Hu/b3BgOnFPACVxbFE5ZVB6ujn5uNQo3a9UBnKkuakOpCr+/pff+GhxaluLkGi4OqtWVAQUspidq2OPWdBGhVFYSlZxIyMDaFRFSFBTe1hy6KsNZpOa8SfHkDFZ2KMbjUoW+AmORi0X4j/ajvpdN7P6ZMZTf1PqZrDbJCGg9a0fIgJDdKIQysguUHiZ+N0CE4KPcB8R17OFcDpENE04tfKWnCUwjj3Lu32OMwZmVKoFKNgfO9Pj0An5T0SXvm08A/VxvKvs82IH3gnWN4of4DgWodMDGzZZBqzXLCtkqcDdR7zBpIDY3Eb1UV1Vcq1pY4DWLiLFBcX/9qhs2r2oECPwfoIYGoFBoaFA6550NN5WLwwYmPdhzMA0QJ6WM03FpBmDCpSReI2NSpvjxlVFE98THjBK0TKRC+rnPcY4utiD+Foy94q2QcfhnD6Mi8b32LjlUmpV6UjqDuTDB6dXcN0H0LQuPTaa783lHcWtrr/57mE08+6K3TZatYmuBHAsOMjEUzEUcyJBdRxYdn0ZYo6sQN2y8kFNTakhh54+2gaVm2N6QYWZNE5eA0NWF1V6876OScX6HNiXEMv260LEl8Q9+++IsZpRwT1nP1edpDL1JelVqlE1jFuhUSarvpG0PVOeMcfxW5tWZGsTrmcYke9PZxn79/qdHbG+rKbnpr9NaKGfvrdTK5+2KP7Ib5omQMFyat6DvTwkUuYsJfM6EesJK0OG2LTyg9GpBAAiCMO+Z5qHiqzpabw+46ZC5LZT0CKIoQMQ9+CPtgnFtJgQ2KTyWU/BTnGm4e69Bg2B7BeEWqmQD+WMCYKXs9JSV9/GB5ukCIS0hD7mgjfTJNWQGf/qU5ejgUgwXNv0hqWy4Qa/2w7uA+jjzlTOArSbStf/4dnFQXbC5j99JyT8uZNV4LoRMWoOJuFT/PVch4JF+thvo74RW0T7sFoOzXTpMLPrn9aCI2ca0D40XEYV0VnlazwYooK6hRWEFS4jYkukuVbFHUQFZvMtAGFwLoZtQvoXYRLywtx9JvTFP8dWb6+/mV+lU4u5fb5Ubj0CHPfO8cPzdW/JHo371KprBeZ1iqJN7aXgQ2tHg3ZsK+keHYSYc/9JuhTiq68Si4f7WIH2fMAPFVEiiBCifMJIiAzZ+95a2cFx7Syt8b3XKaNj/thJwTvR+rUi1OPEYq7uhQ8sXeaDNKS1gI/x0unFvdBpTjsawLV4V83T5+4XgQMNGZiSwtX X-OriginatorOrg: outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: cd9f8288-3320-4835-0893-08dba8909db8 X-MS-Exchange-CrossTenant-AuthSource: TYSPR06MB6433.apcprd06.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 29 Aug 2023 13:05:28.4206 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: PSAPR06MB4406 Subject: [FFmpeg-devel] [PATCH v6] vvcdec: add thread executor X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Cc: Nuo Mi Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: UhV7rxPDumv8 The executor design pattern was introduced by java it also adapted by python Compared to handcrafted thread pool management, it greatly simplifies the thread code. --- doc/APIchanges | 3 + libavutil/Makefile | 2 + libavutil/executor.c | 201 +++++++++++++++++++++++++++++++++++++++++++ libavutil/executor.h | 67 +++++++++++++++ libavutil/version.h | 2 +- 5 files changed, 274 insertions(+), 1 deletion(-) create mode 100644 libavutil/executor.c create mode 100644 libavutil/executor.h diff --git a/doc/APIchanges b/doc/APIchanges index ad1efe708d..06822f22da 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -2,6 +2,9 @@ The last version increases of all libraries were on 2023-02-09 API changes, most recent first: +2023-08-22 - xxxxxxxxxx - lavu 58.18.100 - executor.h + Add AVExecutor API + 2023-08-18 - xxxxxxxxxx - lavu 58.17.100 - channel_layout.h All AV_CHANNEL_LAYOUT_* macros are now compatible with C++ 17 and older. diff --git a/libavutil/Makefile b/libavutil/Makefile index 7828c94dc5..4711f8cde8 100644 --- a/libavutil/Makefile +++ b/libavutil/Makefile @@ -31,6 +31,7 @@ HEADERS = adler32.h \ encryption_info.h \ error.h \ eval.h \ + executor.h \ fifo.h \ file.h \ frame.h \ @@ -127,6 +128,7 @@ OBJS = adler32.o \ encryption_info.o \ error.o \ eval.o \ + executor.o \ fifo.o \ file.o \ file_open.o \ diff --git a/libavutil/executor.c b/libavutil/executor.c new file mode 100644 index 0000000000..0da919f4e8 --- /dev/null +++ b/libavutil/executor.c @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2023 Nuo Mi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "internal.h" +#include "mem.h" +#include "thread.h" + +#include "executor.h" + +#if !HAVE_THREADS + +#define ExecutorThread char + +#define executor_thread_create(t, a, s, ar) 0 +#define executor_thread_join(t, r) do {} while(0) + +#else + +#define ExecutorThread pthread_t + +#define executor_thread_create(t, a, s, ar) pthread_create(t, a, s, ar) +#define executor_thread_join(t, r) pthread_join(t, r) + +#endif //!HAVE_THREADS + +typedef struct ThreadInfo { + AVExecutor *e; + ExecutorThread thread; +} ThreadInfo; + +struct AVExecutor { + AVTaskCallbacks cb; + int thread_count; + + ThreadInfo *threads; + uint8_t *local_contexts; + + AVMutex lock; + AVCond cond; + int die; + + AVTask *tasks; +}; + +static AVTask* remove_task(AVTask **prev, AVTask *t) +{ + *prev = t->next; + t->next = NULL; + return t; +} + +static void add_task(AVTask **prev, AVTask *t) +{ + t->next = *prev; + *prev = t; +} + +static int run_one_task(AVExecutor *e, void *lc) +{ + AVTaskCallbacks *cb = &e->cb; + AVTask **prev; + + for (prev = &e->tasks; *prev && !cb->ready(*prev, cb->user_data); prev = &(*prev)->next) + /* nothing */; + if (*prev) { + AVTask *t = remove_task(prev, *prev); + ff_mutex_unlock(&e->lock); + cb->run(t, lc, cb->user_data); + ff_mutex_lock(&e->lock); + return 1; + } + return 0; +} + +#if HAVE_THREADS +static void *executor_worker_task(void *data) +{ + ThreadInfo *ti = (ThreadInfo*)data; + AVExecutor *e = ti->e; + void *lc = e->local_contexts + (ti - e->threads) * e->cb.local_context_size; + + ff_mutex_lock(&e->lock); + while (1) { + if (e->die) break; + + if (!run_one_task(e, lc)) { + //no task in one loop + ff_cond_wait(&e->cond, &e->lock); + } + } + ff_mutex_unlock(&e->lock); + return NULL; +} +#endif + +static void executor_free(AVExecutor *e, const int has_lock, const int has_cond) +{ + if (e->thread_count) { + //signal die + ff_mutex_lock(&e->lock); + e->die = 1; + ff_cond_broadcast(&e->cond); + ff_mutex_unlock(&e->lock); + + for (int i = 0; i < e->thread_count; i++) + executor_thread_join(e->threads[i].thread, NULL); + } + if (has_cond) + ff_cond_destroy(&e->cond); + if (has_lock) + ff_mutex_destroy(&e->lock); + + av_free(e->threads); + av_free(e->local_contexts); + + av_free(e); +} + +AVExecutor* av_executor_alloc(const AVTaskCallbacks *cb, int thread_count) +{ + AVExecutor *e; + int has_lock = 0, has_cond = 0; + if (!cb || !cb->user_data || !cb->ready || !cb->run || !cb->priority_higher) + return NULL; + + e = av_mallocz(sizeof(*e)); + if (!e) + return NULL; + e->cb = *cb; + + e->local_contexts = av_calloc(thread_count, e->cb.local_context_size); + if (!e->local_contexts) + goto free_executor; + + e->threads = av_calloc(thread_count, sizeof(*e->threads)); + if (!e->threads) + goto free_executor; + + has_lock = !ff_mutex_init(&e->lock, NULL); + has_cond = !ff_cond_init(&e->cond, NULL); + + if (!has_lock || !has_cond) + goto free_executor; + + for (/* nothing */; e->thread_count < thread_count; e->thread_count++) { + ThreadInfo *ti = e->threads + e->thread_count; + ti->e = e; + if (executor_thread_create(&ti->thread, NULL, executor_worker_task, ti)) + goto free_executor; + } + return e; + +free_executor: + executor_free(e, has_lock, has_cond); + return NULL; +} + +void av_executor_free(AVExecutor **executor) +{ + if (!executor || !*executor) + return; + executor_free(*executor, 1, 1); + *executor = NULL; +} + +void av_executor_execute(AVExecutor *e, AVTask *t) +{ + AVTaskCallbacks *cb = &e->cb; + AVTask **prev; + + ff_mutex_lock(&e->lock); + if (t) { + for (prev = &e->tasks; *prev && cb->priority_higher(*prev, t); prev = &(*prev)->next) + /* nothing */; + add_task(prev, t); + } + ff_cond_signal(&e->cond); + ff_mutex_unlock(&e->lock); + +#if !HAVE_THREADS + // We are running in a single-threaded environment, so we must handle all tasks ourselves + while (run_one_task(e, e->local_contexts)) + /* nothing */; +#endif +} diff --git a/libavutil/executor.h b/libavutil/executor.h new file mode 100644 index 0000000000..c3fe44bd0e --- /dev/null +++ b/libavutil/executor.h @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2023 Nuo Mi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVUTIL_EXECUTOR_H +#define AVUTIL_EXECUTOR_H + +typedef struct AVExecutor AVExecutor; +typedef struct AVTask AVTask; + +struct AVTask { + AVTask *next; +}; + +typedef struct AVTaskCallbacks { + void *user_data; + + int local_context_size; + + // return 1 if a's priority > b's priority + int (*priority_higher)(const AVTask *a, const AVTask *b); + + // task is ready for run + int (*ready)(const AVTask *t, void *user_data); + + // run the task + int (*run)(AVTask *t, void *local_context, void *user_data); +} AVTaskCallbacks; + +/** + * Alloc executor + * @param callbacks callback strucutre for executor + * @param thread_count worker thread number + * @return return the executor + */ +AVExecutor* av_executor_alloc(const AVTaskCallbacks *callbacks, int thread_count); + +/** + * Free executor + * @param e pointer to executor + */ +void av_executor_free(AVExecutor **e); + +/** + * Add task to executor + * @param e pointer to executor + * @param t pointer to task. If NULL, it will wakeup one work thread + */ +void av_executor_execute(AVExecutor *e, AVTask *t); + +#endif //AVUTIL_EXECUTOR_H diff --git a/libavutil/version.h b/libavutil/version.h index bc43baca9f..6d27f91cce 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -79,7 +79,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 58 -#define LIBAVUTIL_VERSION_MINOR 17 +#define LIBAVUTIL_VERSION_MINOR 18 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \