From patchwork Tue Aug 22 13:32:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nuo Mi X-Patchwork-Id: 43287 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:1a0a:b0:149:dfde:5c0a with SMTP id cj10csp162052pzb; Tue, 22 Aug 2023 06:33:15 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEUmYqPFVCFAIGT0C8f8fv4bAaG45UQaI2zwHj0NIG8eCmeVZ8YKVg8UklRhn8k264zm3yk X-Received: by 2002:a50:fa93:0:b0:525:d95b:cd46 with SMTP id w19-20020a50fa93000000b00525d95bcd46mr7124258edr.2.1692711195053; Tue, 22 Aug 2023 06:33:15 -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 j20-20020aa7c414000000b00523a48d9983si7076509edq.603.2023.08.22.06.33.14; Tue, 22 Aug 2023 06:33:15 -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=SoyMXHfX; 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 F2B5568C485; Tue, 22 Aug 2023 16:33:10 +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-psaapc01olkn2051.outbound.protection.outlook.com [40.92.52.51]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 3150468BFB1 for ; Tue, 22 Aug 2023 16:33:04 +0300 (EEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=PIV4HX49/NKlU58TOQuSTcaiPcytV6ShaCWr6Jj9uMYyhlYeR65tUNS4UFJVAjwpNjSeD/ulNWq7z9T/5CP6I30xrqEXhSqGum7YPzUnKOkIanD3rh3IJyztuK6ewpANrA8Cw/BON50sV8vQQJa0u0KpGA+FCfstpD6krKYsYyU8caNKeVHmqqlFTcWPeO3OKYDGsvpldv1fg6cGBV4qdNVsuGrT2OAfnTVDY1C59be2IY4e/r6PGE3D7WZGYYb8haksIG65CKFLzBTppgWiqtXD7eqUYsZA66vXy23VDTK8q4ck0n0MnWzuMKpIU10gkyLGoYs/ttNeE+2xAVtGAg== 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=WJMZT0ZN5PcJ1qTbJFts0enZUD+QXFoCaFokCAORD7M=; b=AH1hqjDJTL7zJtJ28erpDvTRqHwE8Tb2lRN1ON/5uCKVa36C4AjTNlIfdOvSL4tOaxQnSQechDOeFCJHemNYnfHpbg9uo4GR86uvFmdnNwix9Mlqp52HvE6zW9fe164bz9qYx8zexyLTrIqq+1m7TqnoaXVPPuYkMdLH/PByk4W2C6oTz2OEO4za2v9bxlG5pL/cMlBwh/dfruB5eA5k8Rirx6lnRGwXpsTfZPjJkeg8yWsQygWgb6bT6dLyNj0Sgj/0YL1W7Hx6DAhCD7rD0TPizPftjbIgS9fwyY55NQpGvO0PpRXIuYraFeD3IMlf0Ut/vaFEJeG1O9MpJsHmTw== 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=WJMZT0ZN5PcJ1qTbJFts0enZUD+QXFoCaFokCAORD7M=; b=SoyMXHfXjoQUXNuZSXnwzW9ABzaHkmuBqA/Jt4MIHcwpTAXXOPzGB4kCDuYLpa1sqjJTAhyUo13JCR00mKxlEBC8sfUGDqVAHKcgoYLoYCUxksMZgWcEm/5EVFaWM8635kRThfD1FewRLP+vlOBKI6A+kSPWbmpm08ush560hG4qD8evSKBPzmJA/EXw+wj8H1cfHrKZfDB57MDf5f15wtJ5PxixIUFIWOdJORPp3g9EIMmUxT3yRaAamBWsYwLD18GH2pDtM6X2ITkGKtPqQFRtSGCu0oyYU+U1nSwY7hq2UCBsNu63nD+S9jh47p9SxPxVihjfHvJ2g8b7rMup8w== Received: from TYSPR06MB6433.apcprd06.prod.outlook.com (2603:1096:400:47a::6) by KL1PR0601MB4050.apcprd06.prod.outlook.com (2603:1096:820:2a::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6699.24; Tue, 22 Aug 2023 13:32:59 +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.020; Tue, 22 Aug 2023 13:32:59 +0000 From: Nuo Mi To: ffmpeg-devel@ffmpeg.org Date: Tue, 22 Aug 2023 21:32:28 +0800 Message-ID: X-Mailer: git-send-email 2.25.1 In-Reply-To: References: X-TMN: [gVFfG6B3rLxncj5AFalCNMGK3inWpxWY] X-ClientProxiedBy: TYAPR01CA0055.jpnprd01.prod.outlook.com (2603:1096:404:2b::19) To TYSPR06MB6433.apcprd06.prod.outlook.com (2603:1096:400:47a::6) X-Microsoft-Original-Message-ID: <20230822133228.7897-1-nuomi2021@gmail.com> MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 2 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: TYSPR06MB6433:EE_|KL1PR0601MB4050:EE_ X-MS-Office365-Filtering-Correlation-Id: 8d6a457a-118e-404f-80f5-08dba3144d13 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: OZj7SYin8ak6AZ1aVrzIeW+mvc1uQxqEkVEdVkeqT/McbqfjuGk90lqPCoXouNXieMY4dA9CnsQBXT5Utl232jgDWO5MJG8aOlFwREw5wCQIY0mCehepMtLN6+wjNgnwlGkhlKA1ZdQpoNMj4dmvvICQOk31cIFbJeFPco6N0SWDbR1aLnxdUmMthFyhk+mcy2dAA7lLQxykIsiuYgEOUKa/GmtT1WWAFcmMtQ7oWDTWbuqMsxRiqnyUAgJbH9PK0nyjJsCr3kCuVA8Z4QklRBTppJJDzcHAyoWrEIl0EQqVAsTES+xMatczXKPUKZgGIP27nyoR8oKWw8C5WJk2z9xM/EJ2cLXSKJV++bnapIKKdZellVsnWNCX7e/pMM/crbV7caIObe+ZKJJWZs0FEfcQdWARgq3oFHxbr6cAnAoq+R8OWa8iG/eYi1nIsi4y8vf6d+LPkoMDKCi0JZA8R6rczRzwKIqZsRj8MXuhRs5AOP4t3rkJZaqqFEUyAyrwFIQpXMlhLFoTSsG5VJVtdl5z1Lx6FG4rVesrEDRBT9FItqhcGAKx280fBmLT7L+pmQtETXccWnvJUXiqoE6JPrWoFeLaiKLowM08ofZR0mK4UuM5fCWfKf3lZra30C67GQ5RfcCrNXbPhJ2G9TB1+A== X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: 0xCScEOHy16hrSOSRoUU0mHpG26tBpHGTid6gr8hyevQ84bdHUl2QH66HgCr9sKqZTBUmUVWR0UAcrbjX35CliWE/mKW1+9MlKQNoUIpyaGT7aSewSoRjK7/j+DeuWqwvseoY/Qis7yQx+pgr0KJLukYqnyJ8l269wEA2QO3O8pbbR48hZAm1tONUxsbGm3XAH/3M1vbme0HZm83t8jKz+dmHKA7fsFJWxLQKOotmxjYaZy9YUPEM+rP1fDC0q2ykXITnk+qbnT7ReKmODG3FsNQ+M6vBrofbdkB2AXjiNhaNhv6fILRGWcp2Yhn9JJHz5iqteKj8sI67Q2MgOZr4K2Dq7xEyiflMe+87qtwkmBcsUFZ9C+Sywj4Gk+0Tgrn71T3m5kgUSHytgtFwR2Z2UJIRfXPRCEkkPJ8NuIBzo2LKfyC8vcbF5AMf/1kA1mzQsfunzWYrQJcoLi+ZurczTRYh9x+NgrS4roaNO+DybkqPi6BYjoS9uUALoh31DvXmT8mAl9KdZy6kaFq9yums2eLRLWhQIawX8neTHo+QNTnlevxJTY67gw17810YVZXGpO1V3nv9/qp6Hku2fe2+ovrgBmwBon6xgnep1MOeWOzTbvFVuo3q6aBzs/H0G1dnN3h8X7ZJbTogVl7KVzDAVHLDsF4aMQpxbmH7oRjtrYxv9WqnRaJ0aYwDeUSQ0prWsqHkp+w4RApv71z8Ay73aAEVeRJEHoomaDp7uqUXeH0iHabSI9bxIgn+kPu2htPW2yNoK1TgXmx1bxVe91DMsxPoUgUKienqZ4L23wNur43zfQQHtPWKU14PyxX8I/YtBhSTtvm4TcVZdcaoBtMGRDQFQV0UeSmze6XSmVq0edMwmBy6gdIwbhvVNNfeYvvaVvUXn0TZ5DCcwnDxtyI/Fcl4Jea+YLTremG5cHUTtrrtJk3RkmH3j/tT278RUqoHUWVNdhkaFUZrDyd4oa9YTjwQi5m/nsMCceprjKeToWdHXnYcNMhqg07QnKn0EZgdKDHJD/CnYTzbqCyi9SW5x9Gd3heskbP0ySREbvSzTqYFvMNlf1fYxNdieGEKlD4AFiBNsqJGi+uAxvpqHcfX4DftozxDmUkwuPIJSrSHFvBJOrGx9SGP9DKQ4+kMUJ+pCuvwPQMXuJIROhX5X4I9OFH5oDtpjbu2+Ty4A5WgRNbVnq94jI/ZFsNp9RMODutz0Hf6YbET7P244kyj5IY/Oa0pkWzNkDXpEIiRgtMPg4RXvJTzScVOXZoxGGORnRt X-OriginatorOrg: outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 8d6a457a-118e-404f-80f5-08dba3144d13 X-MS-Exchange-CrossTenant-AuthSource: TYSPR06MB6433.apcprd06.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 22 Aug 2023 13:32:59.3337 (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: KL1PR0601MB4050 Subject: [FFmpeg-devel] [PATCH v5] 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: +RMyaGOviMq+ The executor design pattern was inroduced 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..38adaef811 --- /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 executor_thread_t char + +#define executor_thread_create(t, a, s, ar) 0 +#define executor_thread_join(t, r) do {} while(0) + +#else + +#define executor_thread_t 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; + executor_thread_t 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, \