From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2206) id 4B03D3860742; Thu, 8 Dec 2022 16:49:33 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4B03D3860742 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1670518173; bh=Bwri8CSYpBBAk4hT9+K3Yig8In6laqiOHelOUG6GtJ4=; h=From:To:Subject:Date:From; b=B5Md+c+gvCOnIKOZ14A55pEcnY8CuR+Tzy0ObeIbxb8XO70G+Jk0mqJcc93WCWmWL 22rR8kuEczGp9FzfgkF/a20di0n4cb40hzX8eCOADX7ifqn8uVWMcspJ6zq2Nda4Zi vXfx6LbUCdH2RezF0FMJ8ZyH8Bz4Y8iK2q0axTOI= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Siddhesh Poyarekar To: glibc-cvs@sourceware.org Subject: [glibc] realloc: Return unchanged if request is within usable size X-Act-Checkin: glibc X-Git-Author: Siddhesh Poyarekar X-Git-Refname: refs/heads/master X-Git-Oldrev: 929ea132b43dbec93e5f4d28f316d37ede91a635 X-Git-Newrev: f4f2ca1509288f6f780af50659693a89949e7e46 Message-Id: <20221208164933.4B03D3860742@sourceware.org> Date: Thu, 8 Dec 2022 16:49:33 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=f4f2ca1509288f6f780af50659693a89949e7e46 commit f4f2ca1509288f6f780af50659693a89949e7e46 Author: Siddhesh Poyarekar Date: Mon Nov 28 12:26:46 2022 -0500 realloc: Return unchanged if request is within usable size If there is enough space in the chunk to satisfy the new size, return the old pointer as is, thus avoiding any locks or reallocations. The only real place this has a benefit is in large chunks that tend to get satisfied with mmap, since there is a large enough spare size (up to a page) for it to matter. For allocations on heap, the extra size is typically barely a few bytes (up to 15) and it's unlikely that it would make much difference in performance. Also added a smoke test to ensure that the old pointer is returned unchanged if the new size to realloc is within usable size of the old pointer. Signed-off-by: Siddhesh Poyarekar Reviewed-by: DJ Delorie Diff: --- malloc/malloc.c | 10 ++++++++++ malloc/tst-realloc.c | 23 +++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/malloc/malloc.c b/malloc/malloc.c index 2a61c8b5ee..ef8c794fb7 100644 --- a/malloc/malloc.c +++ b/malloc/malloc.c @@ -1100,6 +1100,8 @@ static void munmap_chunk(mchunkptr p); static mchunkptr mremap_chunk(mchunkptr p, size_t new_size); #endif +static size_t musable (void *mem); + /* ------------------ MMAP support ------------------ */ @@ -3396,6 +3398,14 @@ __libc_realloc (void *oldmem, size_t bytes) if (__glibc_unlikely (mtag_enabled)) *(volatile char*) oldmem; + /* Return the chunk as is whenever possible, i.e. there's enough usable space + but not so much that we end up fragmenting the block. We use the trim + threshold as the heuristic to decide the latter. */ + size_t usable = musable (oldmem); + if (bytes <= usable + && (unsigned long) (usable - bytes) <= mp_.trim_threshold) + return oldmem; + /* chunk corresponding to oldmem */ const mchunkptr oldp = mem2chunk (oldmem); /* its size */ diff --git a/malloc/tst-realloc.c b/malloc/tst-realloc.c index 5eb62a770f..3b78a2420a 100644 --- a/malloc/tst-realloc.c +++ b/malloc/tst-realloc.c @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -142,6 +143,28 @@ do_test (void) free (p); + /* Smoke test to make sure that allocations do not move if they have enough + space to expand in the chunk. */ + for (size_t sz = 3; sz < 256 * 1024; sz += 2048) + { + p = realloc (NULL, sz); + if (p == NULL) + FAIL_EXIT1 ("realloc (NULL, %zu) returned NULL.", sz); + size_t newsz = malloc_usable_size (p); + printf ("size: %zu, usable size: %zu, extra: %zu\n", + sz, newsz, newsz - sz); + uintptr_t oldp = (uintptr_t) p; + void *new_p = realloc (p, newsz); + if ((uintptr_t) new_p != oldp) + FAIL_EXIT1 ("Expanding (%zu bytes) to usable size (%zu) moved block", + sz, newsz); + free (new_p); + + /* We encountered a large enough extra size at least once. */ + if (newsz - sz > 1024) + break; + } + return 0; }