mirror of
git://sourceware.org/git/glibc.git
synced 2026-09-08 23:58:31 +08:00
Surface-level coalescing in __libc_free_batched_loop
Assisted-by: LLM
This commit is contained in:
+65
-19
@@ -3007,41 +3007,87 @@ tcache_free_init (void *mem)
|
|||||||
__libc_free (mem);
|
__libc_free (mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If the arena does not change between chunks, keep the lock. */
|
/* Adjacent tcache entries are merged locally before touching the heap,
|
||||||
static inline void
|
so that _int_free_merge_chunk is called once for the whole block
|
||||||
__libc_free_batched_loop (bool do_lock, mstate av, mchunkptr p, INTERNAL_SIZE_T size,
|
instead of inserting and immediately unlinking individual chunks.
|
||||||
|
The arena lock acquisition is delayed until the first flush and
|
||||||
|
kept between flushes to the same arena. */
|
||||||
|
static __always_inline void
|
||||||
|
__libc_free_batched_loop (bool do_lock, mchunkptr p, INTERNAL_SIZE_T size,
|
||||||
tcache_perthread_struct *tc, size_t tc_idx)
|
tcache_perthread_struct *tc, size_t tc_idx)
|
||||||
{
|
{
|
||||||
/* Empty half of the tcache, for a hysteresis effect. */
|
/* Empty half of the tcache, for a hysteresis effect. */
|
||||||
unsigned int to_free = mp_.tcache_count / 2;
|
unsigned int to_free = mp_.tcache_count / 2;
|
||||||
|
INTERNAL_SIZE_T chunk_size = size;
|
||||||
|
|
||||||
|
/* The currently locked arena. */
|
||||||
|
mstate av;
|
||||||
if (do_lock)
|
if (do_lock)
|
||||||
__libc_lock_lock (av->mutex);
|
/* Lazily acquire the lock before the first _int_free_merge_chunk call. */
|
||||||
|
av = NULL;
|
||||||
_int_free_merge_chunk (av, p, size);
|
else
|
||||||
|
/* No locking. Chunks are always in the main arena. */
|
||||||
|
av = &main_arena;
|
||||||
|
|
||||||
|
/* Accumulate adjacent chunks from the tcache into [p, p+size)
|
||||||
|
without modifying the heap. Flush to the heap when a
|
||||||
|
non-adjacent chunk is encountered. */
|
||||||
while (tc->entries[tc_idx] != NULL && to_free > 0)
|
while (tc->entries[tc_idx] != NULL && to_free > 0)
|
||||||
{
|
{
|
||||||
void *mem = tcache_get_n (tc, tc_idx, &tc->entries[tc_idx], false);
|
void *mem = tcache_get_n (tc, tc_idx, &tc->entries[tc_idx], false);
|
||||||
p = mem2chunk (mem);
|
mchunkptr q = mem2chunk (mem);
|
||||||
size = chunksize (p);
|
|
||||||
|
|
||||||
/* Lock a different arena if necessary. */
|
if ((char *) q + chunk_size == (char *) p)
|
||||||
if (do_lock)
|
|
||||||
{
|
{
|
||||||
mstate chunk_av = arena_for_chunk (p);
|
/* q is immediately before our block, extend backward. */
|
||||||
if (chunk_av != av)
|
p = q;
|
||||||
|
size += chunk_size;
|
||||||
|
}
|
||||||
|
else if ((char *) p + size == (char *) q)
|
||||||
|
{
|
||||||
|
/* q is immediately after our block, extend forward. */
|
||||||
|
size += chunk_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Not adjacent. Flush the accumulated block. */
|
||||||
|
if (do_lock)
|
||||||
{
|
{
|
||||||
__libc_lock_unlock (av->mutex);
|
mstate new_av = arena_for_chunk (p);
|
||||||
av = chunk_av;
|
if (new_av != av)
|
||||||
__libc_lock_lock (av->mutex);
|
{
|
||||||
|
if (av != NULL)
|
||||||
|
__libc_lock_unlock (av->mutex);
|
||||||
|
av = new_av;
|
||||||
|
__libc_lock_lock (av->mutex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef MALLOC_DEBUG
|
||||||
|
set_head (p, size | (chunksize_nomask (p) & SIZE_BITS));
|
||||||
|
#endif
|
||||||
|
_int_free_merge_chunk (av, p, size);
|
||||||
|
p = q;
|
||||||
|
size = chunk_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
_int_free_merge_chunk (av, p, size);
|
|
||||||
to_free--;
|
to_free--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Flush the remaining accumulated block. */
|
||||||
|
if (do_lock)
|
||||||
|
{
|
||||||
|
mstate new_av = arena_for_chunk (p);
|
||||||
|
if (new_av != av)
|
||||||
|
{
|
||||||
|
if (av != NULL)
|
||||||
|
__libc_lock_unlock (av->mutex);
|
||||||
|
av = new_av;
|
||||||
|
__libc_lock_lock (av->mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#ifdef MALLOC_DEBUG
|
||||||
|
set_head (p, size | (chunksize_nomask (p) & SIZE_BITS));
|
||||||
|
#endif
|
||||||
|
_int_free_merge_chunk (av, p, size);
|
||||||
if (do_lock)
|
if (do_lock)
|
||||||
__libc_lock_unlock (av->mutex);
|
__libc_lock_unlock (av->mutex);
|
||||||
}
|
}
|
||||||
@@ -3058,9 +3104,9 @@ __libc_free_batched (mchunkptr p, INTERNAL_SIZE_T size,
|
|||||||
return malloc_printerr_tail ("free(): invalid size (batch)");
|
return malloc_printerr_tail ("free(): invalid size (batch)");
|
||||||
|
|
||||||
if (SINGLE_THREAD_P)
|
if (SINGLE_THREAD_P)
|
||||||
__libc_free_batched_loop (false, &main_arena, p, size, tc, tc_idx);
|
__libc_free_batched_loop (false, p, size, tc, tc_idx);
|
||||||
else
|
else
|
||||||
__libc_free_batched_loop (true, arena_for_chunk (p), p, size, tc, tc_idx);
|
__libc_free_batched_loop (true, p, size, tc, tc_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
Reference in New Issue
Block a user