From patchwork Wed Jul 19 13:13:00 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Nuo Mi X-Patchwork-Id: 42840 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:b813:b0:130:ccc6:6c4b with SMTP id fi19csp1188220pzb; Wed, 19 Jul 2023 06:27:43 -0700 (PDT) X-Google-Smtp-Source: APBJJlH1yy0NCd3U9sUAhT+0hxYs800BNIM7a8RYh/3XI6NMFj+3FM6iutG3ZoWhfUYe0XBXMdtU X-Received: by 2002:aa7:d50b:0:b0:521:a86d:d596 with SMTP id y11-20020aa7d50b000000b00521a86dd596mr2756994edq.7.1689773263200; Wed, 19 Jul 2023 06:27:43 -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 r21-20020aa7da15000000b005216f02e638si2934217eds.515.2023.07.19.06.27.42; Wed, 19 Jul 2023 06:27:43 -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=UH5jOFma; 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 4A92268C5B0; Wed, 19 Jul 2023 16:27:39 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from APC01-TYZ-obe.outbound.protection.outlook.com (mail-tyzapc01olkn2081.outbound.protection.outlook.com [40.92.107.81]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id DD380680274 for ; Wed, 19 Jul 2023 16:27:32 +0300 (EEST) ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=R1d+lWDaJ5PSUAQuUMtym+wRUpeTAXHCTnqJqQwR5YzNoyk2LYJkNbWmdSY0UpkOJcPjKVoju+SLAqfAGStcx+IySDrNjWJADSYNM2Mf/kcbyMkB/Vnp+3h9RHJ1qywj2oY0iWPHhPRsFMeiAfV6PHj2pcclbve6KP+ivaHeikd8ryU9t8fMLXARzG7LPtrijOW/KT996bWr8AIHy1gryRsv9iHsGy20o/AYqjBSsfBlFTgdw3FnktYimhVQZHl0vcMZ/0xuQ0RfQdJkI1pyyk7pjQM1J4MNDF64KqavJSsVntj3vyetndaldbXyVw0pNmd1ruz0xY3dPmyQHZ9FRw== 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=XKhoVz3TELU14/wUbTaPEoD01WocowhVsDwnn1CZZdk=; b=THkByT0iW3bt8HpGAL5n5RWxlecXepnLTcAzgDb/phf7K3zRPhXMyTeahXnrahpEMHFoLgkjulojvbeZFEo12+iB/35y3xtXyaoMe2QRpj4iywj20FVauFV54nBeOx/4ZAZKrWECpRt6FzZ601oA1hNaFWl2YC0l9jdwc7tIgmLOJYopesbZO5T/KjufHkVRaRHBaIojOx0xvHCWaW8/LGF/ruvr36APTuQQw7kSDCfL4bXfTrJeVYWfGU8Ra4dESSVZoFL8D1XutpgZ64V6uIuCXf3zZLDRHFyvT3+O4sJTROzjjAYnSQ56E3yslR1UwlyJl13pXA9Nnr2EhWMgRQ== 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=XKhoVz3TELU14/wUbTaPEoD01WocowhVsDwnn1CZZdk=; b=UH5jOFmaje8JPR2lFIZCo3o786N2FyMh1iBVhuYeUBZQrvoIJAr9ZtRFvaSXLtycOctXw605u63sm9VFOyy/Kn0F3MYlMoI6lpCeRYZ1K9OlQzAlT20zetflcHKWChLXfyPYilsOyzuJolfUrp6zekcTHAnb89wcGuSSujpBMRE65FNZl1+uCHIqxwClDFxQpSmSJ6CWYOBjLvRvywgRkg9r5AjZaW+fUzA2zLhK3olnobzXnqyEpFzoOHRiHZNAVjfRqHaZieZ3Gv9hfxcowjYCXkgydqvqnxiBfZc2kJFcg36OC6AdSOrqsazYyNNXNUV/EKUQ1PCN/Efa2AD+Pw== Received: from TYSPR06MB6433.apcprd06.prod.outlook.com (2603:1096:400:47a::6) by KL1PR0601MB5568.apcprd06.prod.outlook.com (2603:1096:820:c6::7) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.6609.24; Wed, 19 Jul 2023 13:13:17 +0000 Received: from TYSPR06MB6433.apcprd06.prod.outlook.com ([fe80::e3eb:9950:4dbb:f2cf]) by TYSPR06MB6433.apcprd06.prod.outlook.com ([fe80::e3eb:9950:4dbb:f2cf%4]) with mapi id 15.20.6609.024; Wed, 19 Jul 2023 13:13:17 +0000 From: Nuo Mi To: ffmpeg-devel@ffmpeg.org Date: Wed, 19 Jul 2023 21:13:00 +0800 Message-ID: X-Mailer: git-send-email 2.25.1 In-Reply-To: References: X-TMN: [Gi06eqtavnUIrOfIZ3ntvhhlC/Ze17xV] X-ClientProxiedBy: TYBP286CA0033.JPNP286.PROD.OUTLOOK.COM (2603:1096:404:10a::21) To TYSPR06MB6433.apcprd06.prod.outlook.com (2603:1096:400:47a::6) X-Microsoft-Original-Message-ID: <20230719131300.3120-1-nuomi2021@gmail.com> MIME-Version: 1.0 X-MS-Exchange-MessageSentRepresentingType: 2 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: TYSPR06MB6433:EE_|KL1PR0601MB5568:EE_ X-MS-Office365-Filtering-Correlation-Id: 1e677194-cabd-46e3-c71a-08db8859ea62 X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: eZpDLDCGNX2K9jUjQJIthHgF9sSCOvFAdKN2+aoDYKYo55ag6cep5o6JGKVan5Q80V8JtsVe9FFviDGcmboqj8CIAkiV2qcB0vpLsbI0bTyt+EceJzhaLAHtG+6nEgM4ygsqZEKf+iFF9GMiWVcy0aZTShaPl3+gtwt77TIc0JwjDOfYnjznxqr6FATAcy57QFUaGdULIX5lgEIxg0dm9e4nEU50HNzDoMSYSTG+2X8sD045eu+MpFoK5Tp7dzRzkUu0PFBi0hMFq3WWr7Q1cMdOaJzRHYTsYw6HLWj1LZ+G5fsjxa386msTlY9D5wAYFHb41QQdd0VCz3U82bj+eKop8c85X//RsqWO7X8Edj7Hn9cNvYqytumS+TUM8N9DpXDqI2cUmxUDv7W5vBkUaoAzpuQWf0g5SLHhEuygQLwh3AW6zCoTO2NtdDfU3rlShQbcf0MGNyHFwuEINSXK00/ggcqzcqLwBb0UahPn38ldWI1iwWNkbF+gqwy1eS8WZ1hobQooPRjY8O1W5rXyvjqjWGO+gbLOODL1DIPLsqu73RXSahQp+qc/5UJkvLLUM+mvhMFSd84MHFwYquLF59vjvGBm6nkWqsLWyzZc6cTophnt0mRpwuj74ZIB+OrnCuSvBOIsxBn5+Sgs3DjUlw== X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: T6j+BybR+a+BwQHggPonnhvqKYYfVqi453iPDeGpVRHS0X8WkiOJyNqetUgYx95tRWBaPVlz7W26pLkTODLQ0ZfhMdsO54zirIS66OZhFn7dW+pcZbmVJ1pdh1tNJLhTQ2ML1U/YftITurQLwXhrDEOzV0np8ShucojxRI21KxmidxP+3AWvpfFw+cmSRmF/kIxsTIaY3u60oprO0/f7HPEqvMreqCLIKwuaMc3bnBtnuXtm5iOq+zyOUasv4Bm750abejszkc2G5Zi3wBiVawXRHOB8QOsh22wTL3GRMvd92CmXYBtjQd6EmSXqPXhItDAP30dLCSsPaYYScjd9vME3dZxFvp/VU8tjyPda3Mix1ClYuVMnYsOYh+qvtYIp1y+dk2Hxx/DClk5yMnDARB0ZbQR7Jyu0wj4yNRejJgCsCl8qsKvGZbfHzN89hTA1oWhigz6spOQRA2kWJdxRUnVR2uSw0X4dy9t7IW+ERruf/hTDqYn9PnEN+Pvgg2oGHNBsoz0hKJ5fkLWG/VyGtk9lc3Etr9ycP1pqbTjI8+HVrrdgpDzAJFgJuoacPk8GIlsXY59YHIb5hEtzl9AQVvHinh/qG0iY+azag0LnzyaoZD9405N2/jq0IYp1DXxbLUP/kRkZRnJ58tlWWjVoGECb70N46n+/Txzpp/YGfmm/RjHcaBhtwbDFUCMgDgeNTBBMoF53AgWR/PwaXctTN0tCadJHrz4lJfEYQFHEURR8ozW8FU2mJKLkIMvAOWxpsf+fkrz+hOUI7Hh/5O7/OxGog0oX+KRT+MF+xsduVX04NK2jKpGFB919VBH7JCapj9xUZJUIq1n8c14Geuzq+Ntz7aZMnTt1lyB8dLVlliKxLc20RQA3Dh+3BZEWgUqVfuAR8z0bvcZhRZIko8sGD5/SfdxUPcUlEoozBOj0gI6BEdT4Q7eCQP6Q3meY/jC6y0G5OsaUTiE6yiraweeyuWEfXjHjKhM7/ft26ABXfnwD5bQxzpEK9TFrRS1CZMh6OjA5IuSfutyON4GJNshj5nOuXOsyG+WDOCTLKaTx6oDqO3cWscegYY+v5rqgzRtiM/PLBEHrvpK2rV5EUvhtjdRYGo465XjQiNw3zqIlCE1qczc9DH80ENTrCiFwxCiKnbkKTtYsn2fI9e8+XcsKEzMDxjWxTagVOVmuwVME3To6x35SnbIW79tD8Ft/wfKbcJBD5s6rGlW4yZ0xKmC/tPDZw8Z21dcRrjxMw+p4EX2TJ8Ao7qPfUeZiU2dA2wnd X-OriginatorOrg: outlook.com X-MS-Exchange-CrossTenant-Network-Message-Id: 1e677194-cabd-46e3-c71a-08db8859ea62 X-MS-Exchange-CrossTenant-AuthSource: TYSPR06MB6433.apcprd06.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 19 Jul 2023 13:13:17.1631 (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: KL1PR0601MB5568 Subject: [FFmpeg-devel] [PATCH v3] 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: F0Rv1cnSSnoh 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. --- libavutil/Makefile | 2 + libavutil/executor.c | 201 +++++++++++++++++++++++++++++++++++++++++++ libavutil/executor.h | 67 +++++++++++++++ 3 files changed, 270 insertions(+) create mode 100644 libavutil/executor.c create mode 100644 libavutil/executor.h diff --git a/libavutil/Makefile b/libavutil/Makefile index bd9c6f9e32..b40aacdd06 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 \ @@ -126,6 +127,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..9823fc3d5d --- /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 pthread_create(t, a, s, ar) 0 +#define pthread_join(t, r) do {} while(0) + +#define pthread_cond_init(c, a) 0 +#define pthread_cond_broadcast(c) do {} while(0) +#define pthread_cond_signal(c) do {} while(0) +#define pthread_cond_wait(c, m) do {} while(0) +#define pthread_cond_destroy(c) do {} while(0) + +#define pthread_mutex_init(m, a) 0 +#define pthread_mutex_lock(l) do {} while(0) +#define pthread_mutex_unlock(l) do {} while(0) +#define pthread_mutex_destroy(l) do {} while(0) +#endif + +typedef struct ThreadInfo { + AVExecutor *e; + pthread_t thread; +} ThreadInfo; + +struct AVExecutor { + AVTaskCallbacks cb; + int thread_count; + + ThreadInfo *threads; + uint8_t *local_contexts; + + pthread_mutex_t lock; + pthread_cond_t 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); + pthread_mutex_unlock(&e->lock); + cb->run(t, lc, cb->user_data); + pthread_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; + + pthread_mutex_lock(&e->lock); + while (1) { + if (e->die) break; + + if (!run_one_task(e, lc)) { + //no task in one loop + pthread_cond_wait(&e->cond, &e->lock); + } + } + pthread_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 + pthread_mutex_lock(&e->lock); + e->die = 1; + pthread_cond_broadcast(&e->cond); + pthread_mutex_unlock(&e->lock); + + for (int i = 0; i < e->thread_count; i++) + pthread_join(e->threads[i].thread, NULL); + } + if (has_cond) + pthread_cond_destroy(&e->cond); + if (has_lock) + pthread_mutex_destroy(&e->lock); + + av_free(e->threads); + av_free(e->local_contexts); + + av_free(e); +} + +AVExecutor* avpriv_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_calloc(1, 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 = !pthread_mutex_init(&e->lock, NULL); + has_cond = !pthread_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 (pthread_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 avpriv_executor_free(AVExecutor **executor) +{ + if (!executor || !*executor) + return; + executor_free(*executor, 1, 1); + *executor = NULL; +} + +void avpriv_executor_execute(AVExecutor *e, AVTask *t) +{ + AVTaskCallbacks *cb = &e->cb; + AVTask **prev; + + pthread_mutex_lock(&e->lock); + if (t) { + for (prev = &e->tasks; *prev && cb->priority_higher(*prev, t); prev = &(*prev)->next) + /* nothing */; + add_task(prev, t); + } + pthread_cond_signal(&e->cond); + pthread_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..48c7d47c7d --- /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* avpriv_executor_alloc(const AVTaskCallbacks *callbacks, int thread_count); + +/** + * Free executor + * @param e pointer to executor + */ +void avpriv_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 avpriv_executor_execute(AVExecutor *e, AVTask *t); + +#endif //AVUTIL_EXECUTOR_H