Commit Graph

92 Commits

Author SHA1 Message Date
Florian Weimer
a3b473373e malloc: Avoid premature fallback to mmap [BZ #20284]
Before this change, the while loop in reused_arena which avoids
returning a corrupt arena would never execute its body if the selected
arena were not corrupt.  As a result, result == begin after the loop,
and the function returns NULL, triggering fallback to mmap.
2016-06-21 21:29:21 +02:00
Florian Weimer
92e1ab0eb5 Revert __malloc_initialize_hook symbol poisoning
It turns out the Emacs-internal malloc implementation uses
__malloc_* symbols.  If glibc poisons them in <stdc-pre.h>,
Emacs will no longer compile.
2016-06-20 11:11:29 +02:00
Florian Weimer
2ba3cfa160 malloc: Remove __malloc_initialize_hook from the API [BZ #19564]
__malloc_initialize_hook is interposed by application code, so
the usual approach to define a compatibility symbol does not work.
This commit adds a new mechanism based on #pragma GCC poison in
<stdc-predef.h>.
2016-06-10 10:46:05 +02:00
Florian Weimer
186fe877f3 malloc: Add missing internal_function attributes on function definitions
Fixes build on i386 after commit 29d794863c.
2016-04-14 12:54:22 +02:00
Florian Weimer
8a727af925 malloc: Remove malloc hooks from fork handler
The fork handler now runs so late that there is no risk anymore that
other fork handlers in the same thread use malloc, so it is no
longer necessary to install malloc hooks which made a subset
of malloc functionality available to the thread that called fork.
2016-04-14 09:18:30 +02:00
Florian Weimer
29d794863c malloc: Run fork handler as late as possible [BZ #19431]
Previously, a thread M invoking fork would acquire locks in this order:

  (M1) malloc arena locks (in the registered fork handler)
  (M2) libio list lock

A thread F invoking flush (NULL) would acquire locks in this order:

  (F1) libio list lock
  (F2) individual _IO_FILE locks

A thread G running getdelim would use this order:

  (G1) _IO_FILE lock
  (G2) malloc arena lock

After executing (M1), (F1), (G1), none of the threads can make progress.

This commit changes the fork lock order to:

  (M'1) libio list lock
  (M'2) malloc arena locks

It explicitly encodes the lock order in the implementations of fork,
and does not rely on the registration order, thus avoiding the deadlock.
2016-04-14 09:17:02 +02:00
Florian Weimer
59eda029a8 malloc: Remove NO_THREADS
No functional change.  It was not possible to build without
threading support before.
2016-02-19 17:07:45 +01:00
Florian Weimer
00d4e2ea35 malloc: Remove arena_mem variable
The computed value is never used.  The accesses were data races.
2016-02-19 17:06:33 +01:00
Joseph Myers
f7a9f785e5 Update copyright dates with scripts/update-copyrights. 2016-01-04 16:05:18 +00:00
Florian Weimer
7962541a32 malloc: Update comment for list_lock 2015-12-23 17:23:33 +01:00
Florian Weimer
90c400bd49 malloc: Fix list_lock/arena lock deadlock [BZ #19182]
* malloc/arena.c (list_lock): Document lock ordering requirements.
	(free_list_lock): New lock.
	(ptmalloc_lock_all): Comment on free_list_lock.
	(ptmalloc_unlock_all2): Reinitialize free_list_lock.
	(detach_arena): Update comment.  free_list_lock is now needed.
	(_int_new_arena): Use free_list_lock around detach_arena call.
	Acquire arena lock after list_lock.  Add comment, including FIXME
	about incorrect synchronization.
	(get_free_list): Switch to free_list_lock.
	(reused_arena): Acquire free_list_lock around detach_arena call
	and attached threads counter update.  Add two FIXMEs about
	incorrect synchronization.
	(arena_thread_freeres): Switch to free_list_lock.
	* malloc/malloc.c (struct malloc_state): Update comments to
	mention free_list_lock.
2015-12-21 16:42:46 +01:00
Florian Weimer
3da825ce48 malloc: Fix attached thread reference count handling [BZ #19243]
reused_arena can increase the attached thread count of arenas on the
free list.  This means that the assertion that the reference count is
zero is incorrect.  In this case, the reference count initialization
is incorrect as well and could cause arenas to be put on the free
list too early (while they still have attached threads).

	* malloc/arena.c (get_free_list): Remove assert and adjust
	reference count handling.  Add comment about reused_arena
	interaction.
	(reused_arena): Add comments abount get_free_list interaction.
	* malloc/tst-malloc-thread-exit.c: New file.
	* malloc/Makefile (tests): Add tst-malloc-thread-exit.
	(tst-malloc-thread-exit): Link against libpthread.
2015-12-16 12:39:48 +01:00
Florian Weimer
400e12265d Replace MUTEX_INITIALIZER with _LIBC_LOCK_INITIALIZER in generic code
* sysdeps/mach/hurd/libc-lock.h (_LIBC_LOCK_INITIALIZER): Define.
	(__libc_lock_define_initialized): Use it.
	* sysdeps/nptl/libc-lockP.h (_LIBC_LOCK_INITIALIZER): Define.
	* malloc/arena.c (list_lock): Use _LIBC_LOCK_INITIALIZER.
	* malloc/malloc.c (main_arena): Likewise.
	* sysdeps/generic/malloc-machine.h (MUTEX_INITIALIZER): Remove.
	* sysdeps/nptl/malloc-machine.h (MUTEX_INITIALIZER): Remove.
2015-11-24 16:37:15 +01:00
Florian Weimer
a62719ba90 malloc: Prevent arena free_list from turning cyclic [BZ #19048]
[BZ# 19048]
	* malloc/malloc.c (struct malloc_state): Update comment.  Add
	attached_threads member.
	(main_arena): Initialize attached_threads.
	* malloc/arena.c (list_lock): Update comment.
	(ptmalloc_lock_all, ptmalloc_unlock_all): Likewise.
	(ptmalloc_unlock_all2): Reinitialize arena reference counts.
	(deattach_arena): New function.
	(_int_new_arena): Initialize arena reference count and deattach
	replaced arena.
	(get_free_list, reused_arena): Update reference count and deattach
	replaced arena.
	(arena_thread_freeres): Update arena reference count and only put
	unreferenced arenas on the free list.
2015-10-28 21:29:23 +01:00
Florian Weimer
6782806d8f malloc: Rewrite with explicit TLS access using __thread 2015-10-17 12:06:48 +02:00
Carlos O'Donell
e4bc326dbb malloc: Consistently apply trim_threshold to all heaps (Bug 17195)
In the per-thread arenas we apply trim_threshold-based checks
to the extra space between the pad and the top_area. This isn't
quite accurate and instead we should be harmonizing with the way
in which trim_treshold is applied everywhere else like sysrtim
and _int_free. The trimming check should be based on the size of
the top chunk and only the size of the top chunk. The following
patch harmonizes the trimming and make it consistent for the main
arena and thread arenas.

In the old code a large padding request might have meant that
trimming was not triggered. Now trimming is considered first based
on the chunk, then the pad is subtracted, and the remainder trimmed.
This is how all the other trimmings operate. I didn't measure the
performance difference of this change because it corrects what I
consider to be a behavioural anomaly. We'll need some profile driven
optimization to make this code better, and even there Ondrej and
others have better ideas on how to speedup malloc.

Tested on x86_64 with no regressions. Already reviewed by Siddhesh
Poyarekar and Mel Gorman here and discussed here:
https://sourceware.org/ml/libc-alpha/2015-05/msg00002.html
2015-10-07 22:21:36 -04:00
Siddhesh Poyarekar
c3b9ef8dfc Don't use the main arena in retry path if it is corrupt
If allocation on a non-main arena fails, the main arena is used
without checking to see if it is corrupt.  Add a check that avoids the
main arena if it is corrupt.

	* malloc/arena.c (arena_get_retry): Don't use main_arena if it is
	corrupt.
2015-08-24 14:33:07 +05:30
Siddhesh Poyarekar
92a9b22d70 Drop unused first argument from arena_get2
The arena pointer in the first argument to arena_get2 was used in the
old days before per-thread arenas.  They're unused now and hence can
be dropped.

ChangeLog:

	* malloc/arena.c (arena_get2): Drop unused argument.
	(arena_lock): Adjust.
	(arena_get_retry): Likewise.
2015-08-24 14:32:07 +05:30
Mel Gorman
f8ef472c0f malloc: Do not corrupt the top of a threaded heap if top chunk is MINSIZE [BZ #18502]
mksquashfs was reported in openSUSE to be causing segmentation faults when
creating installation images. Testing showed that mksquashfs sometimes
failed and could be reproduced within 10 attempts. The core dump looked
like the heap top was corrupted and was pointing to an unmapped area. In
other cases, this has been due to an application corrupting glibc structures
but mksquashfs appears to be fine in this regard.

The problem is that heap_trim is "growing" the top into unmapped space.
If the top chunk == MINSIZE then top_area is -1 and this check does not
behave as expected due to a signed/unsigned comparison

  if (top_area <= pad)
    return 0;

The next calculation extra = ALIGN_DOWN(top_area - pad, pagesz) calculates
extra as a negative number which also is unnoticed due to a signed/unsigned
comparison. We then call shrink_heap(heap, negative_number) which crashes
later. This patch adds a simple check against MINSIZE to make sure extra
does not become negative. It adds a cast to hint to the reader that this
is a signed vs unsigned issue.

Without the patch, mksquash fails within 10 attempts. With it applied, it
completed 1000 times without error. The standard test suite "make check"
showed no changes in the summary of test results.
2015-06-26 22:47:45 +02:00
Siddhesh Poyarekar
fff94fa224 Avoid deadlock in malloc on backtrace (BZ #16159)
When the malloc subsystem detects some kind of memory corruption,
depending on the configuration it prints the error, a backtrace, a
memory map and then aborts the process.  In this process, the
backtrace() call may result in a call to malloc, resulting in
various kinds of problematic behavior.

In one case, the malloc it calls may detect a corruption and call
backtrace again, and a stack overflow may result due to the infinite
recursion.  In another case, the malloc it calls may deadlock on an
arena lock with the malloc (or free, realloc, etc.) that detected the
corruption.  In yet another case, if the program is linked with
pthreads, backtrace may do a pthread_once initialization, which
deadlocks on itself.

In all these cases, the program exit is not as intended.  This is
avoidable by marking the arena that malloc detected a corruption on,
as unusable.  The following patch does that.  Features of this patch
are as follows:

- A flag is added to the mstate struct of the arena to indicate if the
  arena is corrupt.

- The flag is checked whenever malloc functions try to get a lock on
  an arena.  If the arena is unusable, a NULL is returned, causing the
  malloc to use mmap or try the next arena.

- malloc_printerr sets the corrupt flag on the arena when it detects a
  corruption

- free does not concern itself with the flag at all.  It is not
  important since the backtrace workflow does not need free.  A free
  in a parallel thread may cause another corruption, but that's not
  new

- The flag check and set are not atomic and may race.  This is fine
  since we don't care about contention during the flag check.  We want
  to make sure that the malloc call in the backtrace does not trip on
  itself and all that action happens in the same thread and not across
  threads.

I verified that the test case does not show any regressions due to
this patch.  I also ran the malloc benchmarks and found an
insignificant difference in timings (< 2%).

	* malloc/Makefile (tests): New test case tst-malloc-backtrace.
	* malloc/arena.c (arena_lock): Check if arena is corrupt.
	(reused_arena): Find a non-corrupt arena.
	(heap_trim): Pass arena to unlink.
	* malloc/hooks.c (malloc_check_get_size): Pass arena to
	malloc_printerr.
	(top_check): Likewise.
	(free_check): Likewise.
	(realloc_check): Likewise.
	* malloc/malloc.c (malloc_printerr): Add arena argument.
	(unlink): Likewise.
	(munmap_chunk): Adjust.
	(ARENA_CORRUPTION_BIT): New macro.
	(arena_is_corrupt): Likewise.
	(set_arena_corrupt): Likewise.
	(sysmalloc): Use mmap if there are no usable arenas.
	(_int_malloc): Likewise.
	(__libc_malloc): Don't fail if arena_get returns NULL.
	(_mid_memalign): Likewise.
	(__libc_calloc): Likewise.
	(__libc_realloc): Adjust for additional argument to
	malloc_printerr.
	(_int_free): Likewise.
	(malloc_consolidate): Likewise.
	(_int_realloc): Likewise.
	(_int_memalign): Don't touch corrupt arenas.
	* malloc/tst-malloc-backtrace.c: New test case.
2015-05-19 06:40:38 +05:30
Mel Gorman
c26efef979 malloc: Consistently apply trim_threshold to all heaps [BZ #17195]
Trimming heaps is a balance between saving memory and the system overhead
required to update page tables and discard allocated pages. The malloc
option M_TRIM_THRESHOLD is a tunable that users are meant to use to decide
where this balance point is but it is only applied to the main arena.

For scalability reasons, glibc malloc has per-thread heaps but these are
shrunk with madvise() if there is one page free at the top of the heap.
In some circumstances this can lead to high system overhead if a thread
has a control flow like

    while (data_to_process) {
        buf = malloc(large_size);
        do_stuff();
        free(buf);
    }

For a large size, the free() will call madvise (pagetable teardown, page
free and TLB flush) every time followed immediately by a malloc (fault,
kernel page alloc, zeroing and charge accounting). The kernel overhead
can dominate such a workload.

This patch allows the user to tune when madvise gets called by applying
the trim threshold to the per-thread heaps and using similar logic to the
main arena when deciding whether to shrink. Alternatively if the dynamic
brk/mmap threshold gets adjusted then the new values will be obeyed by
the per-thread heaps.

Bug 17195 was a test case motivated by a problem encountered in scientific
applications written in python that performance badly due to high page fault
overhead. The basic operation of such a program was posted by Julian Taylor
https://sourceware.org/ml/libc-alpha/2015-02/msg00373.html

With this patch applied, the overhead is eliminated. All numbers in this
report are in seconds and were recorded by running Julian's program 30
times.

pyarray
                                 glibc               madvise
                                  2.21                    v2
System  min             1.81 (  0.00%)        0.00 (100.00%)
System  mean            1.93 (  0.00%)        0.02 ( 99.20%)
System  stddev          0.06 (  0.00%)        0.01 ( 88.99%)
System  max             2.06 (  0.00%)        0.03 ( 98.54%)
Elapsed min             3.26 (  0.00%)        2.37 ( 27.30%)
Elapsed mean            3.39 (  0.00%)        2.41 ( 28.84%)
Elapsed stddev          0.14 (  0.00%)        0.02 ( 82.73%)
Elapsed max             4.05 (  0.00%)        2.47 ( 39.01%)

               glibc     madvise
                2.21          v2
User          141.86      142.28
System         57.94        0.60
Elapsed       102.02       72.66

Note that almost a minutes worth of system time is eliminted and the
program completes 28% faster on average.

To illustrate the problem without python this is a basic test-case for
the worst case scenario where every free is a madvise followed by a an alloc

/* gcc bench-free.c -lpthread -o bench-free */
static int num = 1024;

void __attribute__((noinline,noclone)) dostuff (void *p)
{
}

void *worker (void *data)
{
  int i;

  for (i = num; i--;)
    {
      void *m = malloc (48*4096);
      dostuff (m);
      free (m);
    }

  return NULL;
}

int main()
{
  int i;
  pthread_t t;
  void *ret;
  if (pthread_create (&t, NULL, worker, NULL))
    exit (2);
  if (pthread_join (t, &ret))
    exit (3);
  return 0;
}

Before the patch, this resulted in 1024 calls to madvise. With the patch applied,
madvise is called twice because the default trim threshold is high enough to avoid
this.

This a more complex case where there is a mix of frees. It's simply a different worker
function for the test case above

void *worker (void *data)
{
  int i;
  int j = 0;
  void *free_index[num];

  for (i = num; i--;)
    {
      void *m = malloc ((i % 58) *4096);
      dostuff (m);
      if (i % 2 == 0) {
        free (m);
      } else {
        free_index[j++] = m;
      }
    }
  for (; j >= 0; j--)
    {
      free(free_index[j]);
    }

  return NULL;
}

glibc 2.21 calls malloc 90305 times but with the patch applied, it's
called 13438. Increasing the trim threshold will decrease the number of
times it's called with the option of eliminating the overhead.

ebizzy is meant to generate a workload resembling common web application
server workloads. It is threaded with a large working set that at its core
has an allocation, do_stuff, free loop that also hits this case. The primary
metric of the benchmark is records processed per second. This is running on
my desktop which is a single socket machine with an I7-4770 and 8 cores.
Each thread count was run for 30 seconds. It was only run once as the
performance difference is so high that the variation is insignificant.

                glibc 2.21              patch
threads 1            10230              44114
threads 2            19153              84925
threads 4            34295             134569
threads 8            51007             183387

Note that the saving happens to be a concidence as the size allocated
by ebizzy was less than the default threshold. If a different number of
chunks were specified then it may also be necessary to tune the threshold
to compensate

This is roughly quadrupling the performance of this benchmark. The difference in
system CPU usage illustrates why.

ebizzy running 1 thread with glibc 2.21
10230 records/s 306904
real 30.00 s
user  7.47 s
sys  22.49 s

22.49 seconds was spent in the kernel for a workload runinng 30 seconds. With the
patch applied

ebizzy running 1 thread with patch applied
44126 records/s 1323792
real 30.00 s
user 29.97 s
sys   0.00 s

system CPU usage was zero with the patch applied. strace shows that glibc
running this workload calls madvise approximately 9000 times a second. With
the patch applied madvise was called twice during the workload (or 0.06
times per second).

2015-02-10  Mel Gorman  <mgorman@suse.de>

  [BZ #17195]
  * malloc/arena.c (free): Apply trim threshold to per-thread heaps
    as well as the main arena.
2015-04-02 12:14:14 +05:30
Carlos O'Donell
8a35c3fe12 Use alignment macros, pagesize and powerof2.
We are replacing all of the bespoke alignment code with
ALIGN_UP, ALIGN_DOWN, PTR_ALIGN_UP, and PTR_ALIGN_DOWN.
This cleans up malloc/malloc.c, malloc/arena.c, and
elf/dl-reloc.c. It also makes all the code consistently
use pagesize, and powerof2 as required.

Code size is reduced with the removal of precomputed
pagemask, and use of pagesize instead. No measurable
difference in performance.

No regressions on x86_64.
2015-02-17 19:29:15 -05:00
Joseph Myers
b168057aaa Update copyright dates with scripts/update-copyrights. 2015-01-02 16:29:47 +00:00
Ondřej Bílka
a1ffb40e32 Use glibc_likely instead __builtin_expect. 2014-02-10 15:07:12 +01:00
Ondřej Bílka
bdfe308a16 Remove THREAD_STATS.
A THREAD_STATS macro duplicates gathering information that could be
obtained by systemtap probes instead.
2014-02-10 12:25:04 +01:00
Ondřej Bílka
6c8dbf00f5 Reformat malloc to gnu style. 2014-01-02 09:40:10 +01:00
Allan McRae
d4697bc93d Update copyright notices with scripts/update-copyrights 2014-01-01 22:00:23 +10:00
Ondřej Bílka
5782a80f9f Drop PER_THREAD conditionals from malloc. 2013-12-10 18:00:14 +01:00
Ondřej Bílka
f3eeb3fc56 Replace malloc force_reg by atomic_forced_read. 2013-12-09 17:14:12 +01:00
Alexandre Oliva
322dea0838 Add malloc probes for sbrk and heap resizing.
for ChangeLog

	* malloc/arena.c (new_heap): New memory_heap_new probe.
	(grow_heap): New memory_heap_more probe.
	(shrink_heap): New memory_heap_less probe.
	(heap_trim): New memory_heap_free probe.
	* malloc/malloc.c (sysmalloc): New memory_sbrk_more probe.
	(systrim): New memory_sbrk_less probe.
	* manual/probes.texi: Document them.
2013-09-20 11:54:58 -03:00
Alexandre Oliva
655673f312 Add catch-all alloc retry probe.
for ChangeLog

	* malloc/arena.c (arena_get_retry): Add memory_arena_retry probe.
	* manual/probes.texi: Document it.
2013-09-20 11:50:51 -03:00
Alexandre Oliva
6999d38c95 Add probes for malloc arena changes.
for ChangeLog

	* malloc/arena.c (get_free_list): Add probe
	memory_arena_reuse_free_list.
	(reused_arena) [PER_THREAD]: Add probes memory_arena_reuse_wait
	and memory_arena_reuse.
	(arena_get2) [!PER_THREAD]: Likewise.
	* malloc/malloc.c (__libc_realloc) [!PER_THREAD]: Add probe
	memory_arena_reuse_realloc.
	* manual/probes.texi: Document them.
2013-09-20 11:48:45 -03:00
Alexandre Oliva
3ea5be5436 Add first set of memory probes.
for ChangeLog

	* malloc/malloc.c: Include stap-probe.h.
	(__libc_mallopt): Add memory_mallopt probe.
	* malloc/arena.c (_int_new_arena): Add memory_arena_new probe.
	* manual/probes.texi: New.
	* manual/Makefile (chapters): Add probes.
	* manual/threads.texi: Set next node.
2013-09-20 11:10:54 -03:00
Joseph Myers
a222d91a13 Remove __malloc_ptr_t. 2013-03-08 21:27:42 +00:00
Pino Toscano
2a26ef3a01 Add HAVE_MREMAP for mremap usage
Introduce (only on Linux) and use a HAVE_MREMAP symbol to advertize mremap
availability.

Move the malloc-sysdep.h include from arena.c to malloc.c, since what is
provided by malloc-sysdep.h is needed earlier in malloc.c, before the inclusion
of arena.c.
2013-01-17 21:08:12 +01:00
Joseph Myers
568035b787 Update copyright notices with scripts/update-copyrights. 2013-01-02 19:05:09 +00:00
Roland McGrath
9043e2288e Name space hygeine for madvise. 2012-10-04 16:31:43 -07:00
Siddhesh Poyarekar
9fab36eb58 Shrink heap on linux when overcommit_memory == 2
Using madvise with MADV_DONTNEED to release memory back to the kernel
is not sufficient to change the commit charge accounted against the
process on Linux.  It is OK however, when overcommit is enabled or is
heuristic.  However, when overcommit is restricted to a percentage of
memory setting the contents of /proc/sys/vm/overcommit_memory as 2, it
makes a difference since memory requests will fail.  Hence, we do what
we do with secure exec binaries, which is to call mmap on the region
to be dropped with MAP_FIXED. This internally unmaps the pages in
question and reduces the amount of memory accounted against the
process.
2012-09-25 14:30:52 +05:30
H.J. Lu
ced6f16ee9 Properly handle fencepost with MALLOC_ALIGN_MASK 2012-09-24 08:58:04 -07:00
Siddhesh Poyarekar
c78ab09473 Cleanup code duplication in malloc on fallback to use another arena
Break the fallback code to try another arena into a separate function
for readability.
2012-09-07 14:40:58 +05:30
Alexandre Oliva
24d4e01b22 * malloc/arena.c: Fold copyright years.
* malloc/mcheck.c, malloc/memusage.c: Likewise.
2012-09-05 20:47:16 -03:00
Roland McGrath
750c1f2a9a Make malloc build for no-threads configurations. 2012-08-17 11:29:45 -07:00
Jeff Law
77480c6ba5 Fix whitespace problems detected by commit hooks. 2012-08-10 09:39:58 -06:00
Jeff Law
bf51f568f1 [BZ #13939]
* malloc.c/arena.c (reused_arena): New parameter, avoid_arena.
        When avoid_arena is set, don't retry in the that arena.  Pick the
        next one, whatever it might be.
        (arena_get2): New parameter avoid_arena, pass through to reused_arena.
        (arena_lock): Pass in new parameter to arena_get2.
        * malloc/malloc.c (__libc_memalign): Pass in new parameter to
        arena_get2.
        (__libc_malloc): Unify retrying after main arena failure with
        __libc_memalign version.
        (__libc_valloc, __libc_pvalloc, __libc_calloc): Likewise.
2012-08-10 09:37:52 -06:00
Paul Eggert
59ba27a63a Replace FSF snail mail address with URLs. 2012-02-09 23:18:22 +00:00
Ulrich Drepper
3b49edc04b Cleanups of malloc
Remove ugly names and unnecessary wrappers.
2012-01-31 18:49:22 -05:00
Ulrich Drepper
41b81892f1 Handle ARENA_TEST correctly 2012-01-31 14:42:34 -05:00
Ulrich Drepper
a784e50247 Remove pre-ISO C support
No more __const.
2012-01-07 23:57:22 -05:00
Andreas Schwab
a5fb313cb7 Don't call reused_arena when _int_new_arena failed 2011-11-14 11:53:46 +01:00
Andreas Schwab
77cdc054e0 Check malloc arana limit atomically 2011-11-10 11:00:59 +01:00