From patchwork Thu Dec 26 19:04:07 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andreas Rheinhardt X-Patchwork-Id: 16984 Return-Path: X-Original-To: patchwork@ffaux-bg.ffmpeg.org Delivered-To: patchwork@ffaux-bg.ffmpeg.org Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org [79.124.17.100]) by ffaux.localdomain (Postfix) with ESMTP id B59F7447B3A for ; Thu, 26 Dec 2019 21:04:24 +0200 (EET) Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 9A9AC68A650; Thu, 26 Dec 2019 21:04:24 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-wr1-f51.google.com (mail-wr1-f51.google.com [209.85.221.51]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 11F2668A55D for ; Thu, 26 Dec 2019 21:04:18 +0200 (EET) Received: by mail-wr1-f51.google.com with SMTP id y11so24318591wrt.6 for ; Thu, 26 Dec 2019 11:04:18 -0800 (PST) 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=shz/0QALDwSoS5tOxVwBuyJcgRdYPex8avFpXx1OvF0=; b=j8v0vy+yzp7lleKz0jjGmmgDByMKWtPpi2kqyzn5DWJ/ZPELHWM/CKOlc55D6g3Yfu I9stJpF2V0yM3BNE1uuBRfkcYOf+99IJsxIj+0/OOX5Tu18F/k/tfJyFGBYE2Co/0mOe W/yAyRAeU065t0q0wTqq4DwUbfUlunX4v1YVC6ZGo6X0XD6K2nORXwanxd8JI1tTdAis 3W8ICGTf/ocaSi6B2xPsehdXK9S8VG3zUAIz5pNFJEmkT7hDIYXNhsgIsi8W5+ZiJfEJ 6hX9SpigTneu+RfmMz4dTpNXmc/jgaprQ92yEiTxOTfHJDo0kbbCMyrnwdHnvP+QhxYJ 3TAg== 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=shz/0QALDwSoS5tOxVwBuyJcgRdYPex8avFpXx1OvF0=; b=ekjBqLJIrQ4JgAb0HLXNoFI+qUVC9jKqraJ6U6gCTzs5hxtydcrrAmCLG+dVi2oESh lsPkVCPmHi5NQKQxNGtxk0R74ZE5Z7M2JVZAOEW0yNQ/OTk3KNtTHwnMf+vlH69hdvqG 7T3YZEhjyQ+qHzuO0D7Pwj+nbVoU8I1ykjIYQ3phbMylOVI6UTOv/m1jfaYSZmHzCaU2 oVZC/p8yUtr5C+fhiU5DbZM8rasho1xIcyj4zdUKoDYelEZbE7rfFQR7NJusBVcmtQUg vrMjubXieLV3aMR5/WLw06caV0dUuQ8AtBMPnLTiGuz9+0v8lEgWNZwv45ap3z8dsqSG XcHQ== X-Gm-Message-State: APjAAAWLTvRaUciXGJHV5hkNN1bLiNuPNU+tomBRJCy2AOK8Mf5UcBof PDmWMYkpgMsscrXoqbFo956eE1Cw X-Google-Smtp-Source: APXvYqzxgRKBsSlQ6+kRHXdG0AaBsqbWH419NtZ4Y413KbwGPILorKoiCfXMmwCFbKcmceFtxBz0mQ== X-Received: by 2002:a5d:6349:: with SMTP id b9mr48716331wrw.346.1577387057176; Thu, 26 Dec 2019 11:04:17 -0800 (PST) Received: from sblaptop.fritz.box (ipbcc10203.dynamic.kabel-deutschland.de. [188.193.2.3]) by smtp.gmail.com with ESMTPSA id x11sm8952755wmg.46.2019.12.26.11.04.16 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 26 Dec 2019 11:04:16 -0800 (PST) From: Andreas Rheinhardt To: ffmpeg-devel@ffmpeg.org Date: Thu, 26 Dec 2019 20:04:07 +0100 Message-Id: <20191226190408.26419-1-andreas.rheinhardt@gmail.com> X-Mailer: git-send-email 2.20.1 In-Reply-To: <20191226105342.11175-11-andreas.rheinhardt@gmail.com> References: <20191226105342.11175-11-andreas.rheinhardt@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v2] avutil/mem: Add av_fast_realloc_array() X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.20 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: Andreas Rheinhardt Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" This is an array-equivalent of av_fast_realloc(). Its advantages compared to using av_fast_realloc() for allocating arrays are as follows: a) It performs its own overflow checks for the multiplication that is implicit in array allocations. (And it only needs to perform these checks (as well as the multiplication itself) in case the array needs to be reallocated.) b) It guarantees to not allocated more than UINT_MAX - 1 elements, so the caller needn't check for overflow if the desired size is increased in steps of one. c) Should the caller have increased max_alloc_size, av_fast_realloc() could come in a situation where it allocates more than what fits into an unsigned. In this case the variable containing the allocated size (an unsigned) won't accurately reflect how much has been allocated. After this point, lots of reallocations will happen despite the buffer actually being big enough. d) av_fast_realloc_array() will always allocate in multiples of array elements; no memory is wasted with partial elements. av_fast_realloc() usually allocates size + size / 16 + 32 bytes if size bytes are desired and if the already existing buffer isn't big enough. av_fast_realloc_array() instead allocates nb + (nb + 14) / 16. Rounding up is done in order not to reallocate in steps of one if the current number is < 16; adding 14 instead of 15 has the effect of only allocating one element if one element is desired. This is done with an eye towards applications where arrays might commonly only contain one element (as happens with the Matroska CueTrackPositions). Which of the two functions allocates faster depends upon the size of the elements. E.g. if the elements have a size of 32B and the desired size is incremented in steps of one, allocations happen at 1, 3, 5, 7, 9, 11, 13, 15, 17, 20, 23, 26 ... for av_fast_realloc(), 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 21, 24 ... for av_fast_realloc_array(). For element sizes of 96B, the numbers are 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 21, 23, 25, 27, 30 ... for av_fast_realloc() whereas the pattern for av_fast_realloc_array() is unchanged. Signed-off-by: Andreas Rheinhardt --- I missed that Marton has already pushed his patch for avutil/buffer which also included changes to doc/APIchanges and the lavu version number. Therefore I am resending this to solve the ensuing merge conflict. doc/APIchanges | 3 +++ libavutil/mem.c | 30 ++++++++++++++++++++++++++++++ libavutil/mem.h | 30 ++++++++++++++++++++++++++++++ libavutil/version.h | 2 +- 4 files changed, 64 insertions(+), 1 deletion(-) diff --git a/doc/APIchanges b/doc/APIchanges index 5b8d801f06..b7cede329a 100644 --- a/doc/APIchanges +++ b/doc/APIchanges @@ -15,6 +15,9 @@ libavutil: 2017-10-21 API changes, most recent first: +2019-12-26 - xxxxxxxxxx - lavu 56.38.100 - mem.h + Add av_fast_realloc_array(). + 2019-12-xx - xxxxxxxxxx - lavu 56.37.100 - buffer.h Add av_buffer_pool_buffer_get_opaque(). diff --git a/libavutil/mem.c b/libavutil/mem.c index 88fe09b179..151ab586c4 100644 --- a/libavutil/mem.c +++ b/libavutil/mem.c @@ -497,6 +497,36 @@ void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size) return ptr; } +void *av_fast_realloc_array(void *ptr, unsigned *nb_allocated, + unsigned min_nb, size_t elsize) +{ + unsigned max_nb, nb; + + if (min_nb <= *nb_allocated) + return ptr; + + /* The 16 / 17 implies that we do not need to check + * for overflow in the calculation of nb below. */ + max_nb = FFMIN((UINT_MAX - 1) * 16 / 17, (max_alloc_size - 32) / elsize); + + if (min_nb > max_nb) { + *nb_allocated = 0; + return NULL; + } + + nb = FFMIN(max_nb, min_nb + (min_nb + 14) / 16); + + ptr = av_realloc(ptr, nb * elsize); + /* We could keep *nb_allocated in case of failure, but this is safer + * if the user lost the ptr and uses NULL now. */ + if (!ptr) + nb = 0; + + *nb_allocated = nb; + + return ptr; +} + void av_fast_malloc(void *ptr, unsigned int *size, size_t min_size) { ff_fast_malloc(ptr, size, min_size, 0); diff --git a/libavutil/mem.h b/libavutil/mem.h index 5fb1a02dd9..539a030387 100644 --- a/libavutil/mem.h +++ b/libavutil/mem.h @@ -370,11 +370,41 @@ int av_reallocp_array(void *ptr, size_t nmemb, size_t size); * @return `ptr` if the buffer is large enough, a pointer to newly reallocated * buffer if the buffer was not large enough, or `NULL` in case of * error + * @see av_fast_realloc_array() * @see av_realloc() * @see av_fast_malloc() */ void *av_fast_realloc(void *ptr, unsigned int *size, size_t min_size); +/** + * Reallocate the given array if it is not large enough, otherwise do nothing. + * + * If the given array is `NULL`, then a new uninitialized array is allocated. + * + * If the given array is not large enough, and reallocation fails, `NULL` is + * returned and `*nb_allocated` is set to 0, but the original array is not + * changed or freed. + * + * @param[in,out] ptr Already allocated array, or `NULL` + * @param[in,out] nb_allocated Pointer to the number of elements of the array + * `ptr`. `*nb_allocated` is updated to the new + * number of allocated elements, in particular 0 + * in case of failure. + * @param[in] min_nb Desired minimal amount of elements in array `ptr` + * @param[in] elsize Size of a single element of the array. + * Must not be zero. + * @return `ptr` if the array is large enough, a pointer to newly reallocated + * array if the array was not large enough, or `NULL` in case of + * error + * @note This function will never allocate more than `UINT_MAX - 1` elements, + * so incrementing in steps of one need not be checked for overflow. + * @see av_fast_realloc() + * @see av_realloc() + * @see av_fast_malloc() + */ +void *av_fast_realloc_array(void *ptr, unsigned *nb_allocated, + unsigned min_nb, size_t elsize); + /** * Allocate a buffer, reusing the given one if large enough. * diff --git a/libavutil/version.h b/libavutil/version.h index 4de0fa1fc3..af8f614aff 100644 --- a/libavutil/version.h +++ b/libavutil/version.h @@ -79,7 +79,7 @@ */ #define LIBAVUTIL_VERSION_MAJOR 56 -#define LIBAVUTIL_VERSION_MINOR 37 +#define LIBAVUTIL_VERSION_MINOR 38 #define LIBAVUTIL_VERSION_MICRO 100 #define LIBAVUTIL_VERSION_INT AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \