Reduce external fragmentation in memalign (swbz#14581).
This commit is contained in:
parent
d53844dd72
commit
b21f47f287
192
glibc-fedora-memalign.patch
Normal file
192
glibc-fedora-memalign.patch
Normal file
@ -0,0 +1,192 @@
|
||||
This patch adds a chunk scanning algorithm to the
|
||||
_int_memalign code path that reduces external fragmentation
|
||||
by reusing already aligned chunks instead of looking for
|
||||
chunks of larger sizes and splitting them.
|
||||
|
||||
The goal is it fix the pathological use cases where heaps
|
||||
grow continuously in Ruby or orther workloads that are
|
||||
heavy users of memalign.
|
||||
|
||||
diff --git a/malloc/malloc.c b/malloc/malloc.c
|
||||
index 00ce48cf5879c87f..cc6d8299e272441d 100644
|
||||
--- a/malloc/malloc.c
|
||||
+++ b/malloc/malloc.c
|
||||
@@ -4665,8 +4665,7 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
|
||||
mchunkptr remainder; /* spare room at end to split off */
|
||||
unsigned long remainder_size; /* its size */
|
||||
INTERNAL_SIZE_T size;
|
||||
-
|
||||
-
|
||||
+ mchunkptr victim;
|
||||
|
||||
if (!checked_request2size (bytes, &nb))
|
||||
{
|
||||
@@ -4674,29 +4673,135 @@ _int_memalign (mstate av, size_t alignment, size_t bytes)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
- /*
|
||||
- Strategy: find a spot within that chunk that meets the alignment
|
||||
+ /* Strategy: search the bins looking for an existing block that meets
|
||||
+ our needs. */
|
||||
+
|
||||
+ /* This will be set if we found a candidate chunk. */
|
||||
+ victim = NULL;
|
||||
+
|
||||
+ /* Fast bins are singly-linked, hard to remove a chunk from the middle
|
||||
+ and unlikely to meet our alignment requirements. We have not done
|
||||
+ any experimentation with searching for aligned fastbins. */
|
||||
+
|
||||
+ if (in_smallbin_range (nb))
|
||||
+ {
|
||||
+ /* Check small bins. Small bin chunks are doubly-linked despite
|
||||
+ being the same size. */
|
||||
+ int victim_index; /* its bin index */
|
||||
+
|
||||
+ victim_index = smallbin_index (nb);
|
||||
+ mchunkptr fwd; /* misc temp for linking */
|
||||
+ mchunkptr bck; /* misc temp for linking */
|
||||
+
|
||||
+ bck = bin_at (av, victim_index);
|
||||
+ fwd = bck->fd;
|
||||
+ while (fwd != bck)
|
||||
+ {
|
||||
+ if (((intptr_t)chunk2mem (fwd) & (alignment - 1)) == 0)
|
||||
+ {
|
||||
+ victim = fwd;
|
||||
+
|
||||
+ /* Unlink it */
|
||||
+ victim->fd->bk = victim->bk;
|
||||
+ victim->bk->fd = victim->fd;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ fwd = fwd->fd;
|
||||
+ }
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* Check large bins. */
|
||||
+ int victim_index; /* its bin index */
|
||||
+ mchunkptr fwd; /* misc temp for linking */
|
||||
+ mchunkptr bck; /* misc temp for linking */
|
||||
+ mchunkptr best = NULL;
|
||||
+ size_t best_size = 0;
|
||||
+
|
||||
+ victim_index = largebin_index (nb);
|
||||
+ bck = bin_at (av, victim_index);
|
||||
+ fwd = bck->fd;
|
||||
+
|
||||
+ while (fwd != bck)
|
||||
+ {
|
||||
+ if (chunksize (fwd) >= nb
|
||||
+ && (((intptr_t)chunk2mem (fwd) & (alignment - 1)) == 0)
|
||||
+ && (chunksize (fwd) <= best_size || best == NULL))
|
||||
+ {
|
||||
+ best = fwd;
|
||||
+ best_size = chunksize(fwd);
|
||||
+ }
|
||||
+
|
||||
+ fwd = fwd->fd;
|
||||
+ if (chunksize (fwd) < nb)
|
||||
+ break;
|
||||
+ }
|
||||
+ victim = best;
|
||||
+
|
||||
+ if (victim)
|
||||
+ {
|
||||
+ if (victim->fd_nextsize)
|
||||
+ {
|
||||
+ if (victim->fd_nextsize != victim->fd
|
||||
+ && victim->fd != bck)
|
||||
+ {
|
||||
+ /* There's more with the same size, but we've chosen the
|
||||
+ "leader". We need to make the next one the leader. */
|
||||
+ victim->fd->fd_nextsize = victim->fd_nextsize;
|
||||
+ victim->fd->bk_nextsize = victim->bk_nextsize;
|
||||
+ if (victim->fd_nextsize)
|
||||
+ victim->fd_nextsize->bk_nextsize = victim->fd;
|
||||
+ if (victim->bk_nextsize)
|
||||
+ victim->bk_nextsize->fd_nextsize = victim->fd;
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* There's only this one with this size. */
|
||||
+ if (victim->fd_nextsize)
|
||||
+ victim->fd_nextsize->bk_nextsize = victim->bk_nextsize;
|
||||
+ if (victim->bk_nextsize)
|
||||
+ victim->bk_nextsize->fd_nextsize = victim->fd_nextsize;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (victim->fd)
|
||||
+ victim->fd->bk = victim->bk;
|
||||
+ if (victim->bk)
|
||||
+ victim->bk->fd = victim->fd;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* Strategy: find a spot within that chunk that meets the alignment
|
||||
request, and then possibly free the leading and trailing space.
|
||||
- */
|
||||
+ This strategy is incredibly costly and can lead to external
|
||||
+ fragmentation if header and footer chunks are unused. */
|
||||
|
||||
- /* Call malloc with worst case padding to hit alignment. */
|
||||
+ if (victim != NULL)
|
||||
+ {
|
||||
+ p = victim;
|
||||
+ m = chunk2mem (p);
|
||||
+ set_inuse (p);
|
||||
+ }
|
||||
+ else
|
||||
+ {
|
||||
+ /* Call malloc with worst case padding to hit alignment. */
|
||||
|
||||
- m = (char *) (_int_malloc (av, nb + alignment + MINSIZE));
|
||||
+ m = (char *) (_int_malloc (av, nb + alignment + MINSIZE));
|
||||
|
||||
- if (m == 0)
|
||||
- return 0; /* propagate failure */
|
||||
+ if (m == 0)
|
||||
+ return 0; /* propagate failure */
|
||||
|
||||
- p = mem2chunk (m);
|
||||
+ p = mem2chunk (m);
|
||||
+ }
|
||||
|
||||
if ((((unsigned long) (m)) % alignment) != 0) /* misaligned */
|
||||
-
|
||||
- { /*
|
||||
- Find an aligned spot inside chunk. Since we need to give back
|
||||
- leading space in a chunk of at least MINSIZE, if the first
|
||||
- calculation places us at a spot with less than MINSIZE leader,
|
||||
- we can move to the next aligned spot -- we've allocated enough
|
||||
- total room so that this is always possible.
|
||||
- */
|
||||
+ {
|
||||
+ /* Find an aligned spot inside chunk. Since we need to give back
|
||||
+ leading space in a chunk of at least MINSIZE, if the first
|
||||
+ calculation places us at a spot with less than MINSIZE leader,
|
||||
+ we can move to the next aligned spot -- we've allocated enough
|
||||
+ total room so that this is always possible. */
|
||||
brk = (char *) mem2chunk (((unsigned long) (m + alignment - 1)) &
|
||||
- ((signed long) alignment));
|
||||
if ((unsigned long) (brk - (char *) (p)) < MINSIZE)
|
||||
@@ -5385,6 +5490,16 @@ __malloc_info (int options, FILE *fp)
|
||||
|
||||
fputs ("<malloc version=\"1\">\n", fp);
|
||||
|
||||
+ fprintf (fp, "<malloc_alignment bytes=\"%ld\" />\n", (long) MALLOC_ALIGNMENT);
|
||||
+ fprintf (fp, "<min_chunk_size bytes=\"%ld\" />\n", (long) MIN_CHUNK_SIZE);
|
||||
+ fprintf (fp, "<max_fast_alloc bytes=\"%ld\" />\n", (long) MAX_FAST_SIZE);
|
||||
+ fprintf (fp, "<max_tcache_alloc bytes=\"%ld\" />\n", (long) MAX_TCACHE_SIZE);
|
||||
+ fprintf (fp, "<min_large_alloc bytes=\"%ld\" />\n", (long) MIN_LARGE_SIZE);
|
||||
+ fprintf (fp, "<default_mmap_threshold bytes=\"%ld\" />\n", (long) DEFAULT_MMAP_THRESHOLD);
|
||||
+ fprintf (fp, "<max_mmap_threshold bytes=\"%ld\" />\n", (long) DEFAULT_MMAP_THRESHOLD_MAX);
|
||||
+ fprintf (fp, "<heap_min_size bytes=\"%ld\" />\n", (long) HEAP_MIN_SIZE);
|
||||
+ fprintf (fp, "<heap_max_size bytes=\"%ld\" />\n", (long) HEAP_MAX_SIZE);
|
||||
+
|
||||
/* Iterate over all arenas currently in use. */
|
||||
mstate ar_ptr = &main_arena;
|
||||
do
|
@ -87,7 +87,7 @@
|
||||
Summary: The GNU libc libraries
|
||||
Name: glibc
|
||||
Version: %{glibcversion}
|
||||
Release: 29%{?dist}
|
||||
Release: 30%{?dist}
|
||||
|
||||
# In general, GPLv2+ is used by programs, LGPLv2+ is used for
|
||||
# libraries.
|
||||
@ -159,6 +159,9 @@ Patch28: glibc-rh1615608.patch
|
||||
# In progress upstream submission for nscd.conf changes:
|
||||
# https://www.sourceware.org/ml/libc-alpha/2019-03/msg00436.html
|
||||
Patch31: glibc-fedora-nscd-warnings.patch
|
||||
Patch32: glibc-fedora-memalign.patch
|
||||
|
||||
|
||||
|
||||
##############################################################################
|
||||
# Continued list of core "glibc" package information:
|
||||
@ -2015,6 +2018,9 @@ fi
|
||||
%files -f compat-libpthread-nonshared.filelist -n compat-libpthread-nonshared
|
||||
|
||||
%changelog
|
||||
* Fri Jun 21 2019 Carlos O'Donell <carlos@redhat.com> - 2.29.9000-30
|
||||
- Reduce external fragmentation in memalign (swbz#14581)
|
||||
|
||||
* Fri Jun 21 2019 Florian Weimer <fweimer@redhat.com> - 2.29.9000-29
|
||||
- Auto-sync with upstream branch master,
|
||||
commit 21cc130b78a4db9113fb6695e2b951e697662440:
|
||||
|
Loading…
Reference in New Issue
Block a user